From 30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:48:11 +0500 Subject: [PATCH 01/13] feat: [Many APIs] Add REST Interceptors which support reading metadata (#13503) BEGIN_COMMIT_OVERRIDE feat: Add REST Interceptors which support reading metadata feat: Add support for reading selective GAPIC generation methods from service YAML chore: Update gapic-generator-python to v1.22.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. feat: Add support for reading selective GAPIC generation methods from service YAML chore: Update gapic-generator-python to v1.22.0 PiperOrigin-RevId: 724026024 Source-Link: https://github.com/googleapis/googleapis/commit/ad9963857109513e77eed153a66264481789109f Source-Link: https://github.com/googleapis/googleapis-gen/commit/e291c4dd1d670eda19998de76f967e1603a48993 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLW1hcHMtbWFwc3BsYXRmb3JtZGF0YXNldHMvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLW1hcHMtcm91dGVvcHRpbWl6YXRpb24vLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLW1hcHMtcm91dGluZy8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLW1hcHMtc29sYXIvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLWNzcy8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWFjY291bnRzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWNvbnZlcnNpb25zLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWRhdGFzb3VyY2VzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWludmVudG9yaWVzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWxmcC8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LW5vdGlmaWNhdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXByb2R1Y3RzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXByb21vdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXF1b3RhLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXJlcG9ydHMvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXJldmlld3MvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLXR5cGUvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ3JhZmVhcy8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 --------- Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .../README.rst | 4 +- .../mapsplatformdatasets/gapic_version.py | 2 +- .../mapsplatformdatasets_v1/gapic_version.py | 2 +- .../services/maps_platform_datasets/client.py | 29 ++ .../maps_platform_datasets/transports/rest.py | 161 +++++++- .../noxfile.py | 81 +++- ...a_google.maps.mapsplatformdatasets.v1.json | 2 +- .../test_maps_platform_datasets.py | 85 ++++ .../google-maps-routeoptimization/README.rst | 4 +- .../maps/routeoptimization/gapic_version.py | 2 +- .../routeoptimization_v1/gapic_version.py | 2 +- .../services/route_optimization/client.py | 51 ++- .../route_optimization/transports/rest.py | 65 ++- .../google-maps-routeoptimization/noxfile.py | 81 +++- ...data_google.maps.routeoptimization.v1.json | 2 +- .../test_route_optimization.py | 64 +++ packages/google-maps-routing/README.rst | 4 +- .../google/maps/routing/gapic_version.py | 2 +- .../google/maps/routing_v2/gapic_version.py | 2 +- .../maps/routing_v2/services/routes/client.py | 29 ++ .../services/routes/transports/rest.py | 66 +++- packages/google-maps-routing/noxfile.py | 81 +++- ...ippet_metadata_google.maps.routing.v2.json | 2 +- .../unit/gapic/routing_v2/test_routes.py | 63 +++ packages/google-maps-solar/README.rst | 4 +- .../google/maps/solar/gapic_version.py | 2 +- .../google/maps/solar_v1/gapic_version.py | 2 +- .../maps/solar_v1/services/solar/client.py | 29 ++ .../services/solar/transports/rest.py | 96 ++++- packages/google-maps-solar/noxfile.py | 81 +++- ...snippet_metadata_google.maps.solar.v1.json | 2 +- .../tests/unit/gapic/solar_v1/test_solar.py | 66 ++++ packages/google-shopping-css/README.rst | 4 +- .../google/shopping/css/gapic_version.py | 2 +- .../google/shopping/css_v1/gapic_version.py | 2 +- .../services/account_labels_service/client.py | 29 ++ .../account_labels_service/transports/rest.py | 96 ++++- .../services/accounts_service/client.py | 29 ++ .../accounts_service/transports/rest.py | 95 ++++- .../css_product_inputs_service/client.py | 29 ++ .../transports/rest.py | 66 +++- .../services/css_products_service/client.py | 29 ++ .../css_products_service/transports/rest.py | 64 ++- packages/google-shopping-css/noxfile.py | 81 +++- ...ippet_metadata_google.shopping.css.v1.json | 2 +- .../css_v1/test_account_labels_service.py | 71 ++++ .../gapic/css_v1/test_accounts_service.py | 66 ++++ .../css_v1/test_css_product_inputs_service.py | 62 +++ .../gapic/css_v1/test_css_products_service.py | 65 +++ .../README.rst | 4 +- .../merchant_accounts/gapic_version.py | 2 +- .../merchant_accounts_v1beta/gapic_version.py | 2 +- .../services/account_issue_service/client.py | 29 ++ .../account_issue_service/transports/rest.py | 33 +- .../services/account_tax_service/client.py | 29 ++ .../account_tax_service/transports/rest.py | 95 ++++- .../services/accounts_service/client.py | 29 ++ .../accounts_service/transports/rest.py | 157 +++++++- .../autofeed_settings_service/client.py | 29 ++ .../transports/rest.py | 66 +++- .../business_identity_service/client.py | 29 ++ .../transports/rest.py | 66 +++- .../services/business_info_service/client.py | 29 ++ .../business_info_service/transports/rest.py | 62 ++- .../email_preferences_service/client.py | 29 ++ .../transports/rest.py | 66 +++- .../services/homepage_service/client.py | 29 ++ .../homepage_service/transports/rest.py | 124 +++++- .../online_return_policy_service/client.py | 29 ++ .../transports/rest.py | 67 +++- .../services/programs_service/client.py | 29 ++ .../programs_service/transports/rest.py | 124 +++++- .../services/regions_service/client.py | 29 ++ .../regions_service/transports/rest.py | 124 +++++- .../shipping_settings_service/client.py | 29 ++ .../transports/rest.py | 66 +++- .../client.py | 29 ++ .../transports/rest.py | 74 +++- .../terms_of_service_service/client.py | 29 ++ .../transports/rest.py | 65 ++- .../services/user_service/client.py | 29 ++ .../services/user_service/transports/rest.py | 122 +++++- .../noxfile.py | 81 +++- ...gle.shopping.merchant.accounts.v1beta.json | 2 +- .../test_account_issue_service.py | 59 +++ .../test_account_tax_service.py | 68 ++++ .../test_accounts_service.py | 77 ++++ .../test_autofeed_settings_service.py | 62 +++ .../test_business_identity_service.py | 62 +++ .../test_business_info_service.py | 62 +++ .../test_email_preferences_service.py | 62 +++ .../test_homepage_service.py | 70 ++++ .../test_online_return_policy_service.py | 68 ++++ .../test_programs_service.py | 70 ++++ .../test_regions_service.py | 70 ++++ .../test_shipping_settings_service.py | 62 +++ ...erms_of_service_agreement_state_service.py | 68 ++++ .../test_terms_of_service_service.py | 62 +++ .../test_user_service.py | 70 ++++ .../README.rst | 4 +- .../merchant_conversions/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../conversion_sources_service/client.py | 29 ++ .../transports/rest.py | 166 +++++++- .../noxfile.py | 81 +++- ....shopping.merchant.conversions.v1beta.json | 2 +- .../test_conversion_sources_service.py | 83 ++++ .../README.rst | 4 +- .../merchant_datasources/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../services/data_sources_service/client.py | 29 ++ .../data_sources_service/transports/rest.py | 126 +++++- .../services/file_uploads_service/client.py | 29 ++ .../file_uploads_service/transports/rest.py | 31 +- .../noxfile.py | 81 +++- ....shopping.merchant.datasources.v1beta.json | 2 +- .../test_data_sources_service.py | 77 ++++ .../test_file_uploads_service.py | 56 +++ .../README.rst | 4 +- .../merchant_inventories/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../local_inventory_service/client.py | 29 ++ .../transports/rest.py | 65 ++- .../regional_inventory_service/client.py | 29 ++ .../transports/rest.py | 67 +++- .../noxfile.py | 81 +++- ....shopping.merchant.inventories.v1beta.json | 2 +- .../test_local_inventory_service.py | 65 +++ .../test_regional_inventory_service.py | 68 ++++ .../google-shopping-merchant-lfp/README.rst | 4 +- .../shopping/merchant_lfp/gapic_version.py | 2 +- .../merchant_lfp_v1beta/gapic_version.py | 2 +- .../services/lfp_inventory_service/client.py | 29 ++ .../lfp_inventory_service/transports/rest.py | 31 +- .../services/lfp_sale_service/client.py | 29 ++ .../lfp_sale_service/transports/rest.py | 31 +- .../services/lfp_store_service/client.py | 29 ++ .../lfp_store_service/transports/rest.py | 93 ++++- .../google-shopping-merchant-lfp/noxfile.py | 81 +++- ...a_google.shopping.merchant.lfp.v1beta.json | 2 +- .../test_lfp_inventory_service.py | 56 +++ .../test_lfp_sale_service.py | 55 +++ .../test_lfp_store_service.py | 65 +++ .../README.rst | 4 +- .../merchant_notifications/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../notifications_api_service/client.py | 29 ++ .../transports/rest.py | 148 ++++++- .../noxfile.py | 81 +++- ...hopping.merchant.notifications.v1beta.json | 2 +- .../test_notifications_api_service.py | 86 ++++ .../README.rst | 4 +- .../merchant_products/gapic_version.py | 2 +- .../merchant_products_v1beta/gapic_version.py | 2 +- .../services/product_inputs_service/client.py | 29 ++ .../product_inputs_service/transports/rest.py | 31 +- .../services/products_service/client.py | 29 ++ .../products_service/transports/rest.py | 62 ++- .../noxfile.py | 81 +++- ...gle.shopping.merchant.products.v1beta.json | 2 +- .../test_product_inputs_service.py | 56 +++ .../test_products_service.py | 60 +++ .../README.rst | 4 +- .../merchant_promotions/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../services/promotions_service/client.py | 29 ++ .../promotions_service/transports/rest.py | 95 ++++- .../noxfile.py | 81 +++- ...e.shopping.merchant.promotions.v1beta.json | 2 +- .../test_promotions_service.py | 67 ++++ .../google-shopping-merchant-quota/README.rst | 4 +- .../shopping/merchant_quota/gapic_version.py | 2 +- .../merchant_quota_v1beta/gapic_version.py | 2 +- .../services/quota_service/client.py | 29 ++ .../services/quota_service/transports/rest.py | 31 +- .../google-shopping-merchant-quota/noxfile.py | 81 +++- ...google.shopping.merchant.quota.v1beta.json | 2 +- .../test_quota_service.py | 55 +++ .../README.rst | 4 +- .../merchant_reports/gapic_version.py | 2 +- .../merchant_reports_v1beta/gapic_version.py | 2 +- .../services/report_service/client.py | 29 ++ .../report_service/transports/rest.py | 31 +- .../noxfile.py | 81 +++- ...ogle.shopping.merchant.reports.v1beta.json | 2 +- .../test_report_service.py | 55 +++ .../README.rst | 4 +- .../merchant_reviews/gapic_version.py | 2 +- .../merchant_reviews_v1beta/gapic_version.py | 2 +- .../merchant_reviews_service/client.py | 29 ++ .../transports/rest.py | 96 ++++- .../product_reviews_service/client.py | 29 ++ .../transports/rest.py | 96 ++++- .../noxfile.py | 81 +++- .../test_merchant_reviews_service.py | 71 ++++ .../test_product_reviews_service.py | 71 ++++ packages/google-shopping-type/README.rst | 4 +- .../google/shopping/type/gapic_version.py | 2 +- packages/google-shopping-type/noxfile.py | 81 +++- packages/grafeas/README.rst | 4 +- .../grafeas/grafeas/grafeas/gapic_version.py | 2 +- .../grafeas/grafeas_v1/gapic_version.py | 2 +- .../grafeas_v1/services/grafeas/client.py | 2 + .../services/grafeas/transports/rest.py | 372 ++++++++++++++++-- packages/grafeas/noxfile.py | 81 +++- .../snippet_metadata_grafeas.v1.json | 2 +- .../unit/gapic/grafeas_v1/test_grafeas.py | 73 ++++ .../unique-grafeas-client.yaml | 70 ++++ 208 files changed, 8746 insertions(+), 356 deletions(-) diff --git a/packages/google-maps-mapsplatformdatasets/README.rst b/packages/google-maps-mapsplatformdatasets/README.rst index d0d0a1fd2b4c..658ebfd974ad 100644 --- a/packages/google-maps-mapsplatformdatasets/README.rst +++ b/packages/google-maps-mapsplatformdatasets/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Maps Platform Datasets API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Maps Platform Datasets API.: https://developers.google.com/maps -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py index de37524e4ed5..558c8aab67c5 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py index de37524e4ed5..558c8aab67c5 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/client.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/client.py index 807d23c116a2..4bbfd2ce91cf 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/client.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -486,6 +488,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/transports/rest.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/transports/rest.py index 081d4798e807..c63b29831365 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/transports/rest.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/services/maps_platform_datasets/transports/rest.py @@ -139,12 +139,35 @@ def pre_create_dataset( def post_create_dataset(self, response: gmm_dataset.Dataset) -> gmm_dataset.Dataset: """Post-rpc interceptor for create_dataset - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_dataset_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MapsPlatformDatasets server but before - it is returned to user code. + it is returned to user code. This `post_create_dataset` interceptor runs + before the `post_create_dataset_with_metadata` interceptor. """ return response + def post_create_dataset_with_metadata( + self, + response: gmm_dataset.Dataset, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gmm_dataset.Dataset, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_dataset + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MapsPlatformDatasets server but before it is returned to user code. + + We recommend only using this `post_create_dataset_with_metadata` + interceptor in new development instead of the `post_create_dataset` interceptor. + When both interceptors are used, this `post_create_dataset_with_metadata` interceptor runs after the + `post_create_dataset` interceptor. The (possibly modified) response returned by + `post_create_dataset` will be passed to + `post_create_dataset_with_metadata`. + """ + return response, metadata + def pre_delete_dataset( self, request: maps_platform_datasets.DeleteDatasetRequest, @@ -180,12 +203,38 @@ def post_fetch_dataset_errors( ) -> maps_platform_datasets.FetchDatasetErrorsResponse: """Post-rpc interceptor for fetch_dataset_errors - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_fetch_dataset_errors_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MapsPlatformDatasets server but before - it is returned to user code. + it is returned to user code. This `post_fetch_dataset_errors` interceptor runs + before the `post_fetch_dataset_errors_with_metadata` interceptor. """ return response + def post_fetch_dataset_errors_with_metadata( + self, + response: maps_platform_datasets.FetchDatasetErrorsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + maps_platform_datasets.FetchDatasetErrorsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for fetch_dataset_errors + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MapsPlatformDatasets server but before it is returned to user code. + + We recommend only using this `post_fetch_dataset_errors_with_metadata` + interceptor in new development instead of the `post_fetch_dataset_errors` interceptor. + When both interceptors are used, this `post_fetch_dataset_errors_with_metadata` interceptor runs after the + `post_fetch_dataset_errors` interceptor. The (possibly modified) response returned by + `post_fetch_dataset_errors` will be passed to + `post_fetch_dataset_errors_with_metadata`. + """ + return response, metadata + def pre_get_dataset( self, request: maps_platform_datasets.GetDatasetRequest, @@ -204,12 +253,35 @@ def pre_get_dataset( def post_get_dataset(self, response: dataset.Dataset) -> dataset.Dataset: """Post-rpc interceptor for get_dataset - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_dataset_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MapsPlatformDatasets server but before - it is returned to user code. + it is returned to user code. This `post_get_dataset` interceptor runs + before the `post_get_dataset_with_metadata` interceptor. """ return response + def post_get_dataset_with_metadata( + self, + response: dataset.Dataset, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[dataset.Dataset, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_dataset + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MapsPlatformDatasets server but before it is returned to user code. + + We recommend only using this `post_get_dataset_with_metadata` + interceptor in new development instead of the `post_get_dataset` interceptor. + When both interceptors are used, this `post_get_dataset_with_metadata` interceptor runs after the + `post_get_dataset` interceptor. The (possibly modified) response returned by + `post_get_dataset` will be passed to + `post_get_dataset_with_metadata`. + """ + return response, metadata + def pre_list_datasets( self, request: maps_platform_datasets.ListDatasetsRequest, @@ -230,12 +302,38 @@ def post_list_datasets( ) -> maps_platform_datasets.ListDatasetsResponse: """Post-rpc interceptor for list_datasets - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_datasets_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MapsPlatformDatasets server but before - it is returned to user code. + it is returned to user code. This `post_list_datasets` interceptor runs + before the `post_list_datasets_with_metadata` interceptor. """ return response + def post_list_datasets_with_metadata( + self, + response: maps_platform_datasets.ListDatasetsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + maps_platform_datasets.ListDatasetsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_datasets + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MapsPlatformDatasets server but before it is returned to user code. + + We recommend only using this `post_list_datasets_with_metadata` + interceptor in new development instead of the `post_list_datasets` interceptor. + When both interceptors are used, this `post_list_datasets_with_metadata` interceptor runs after the + `post_list_datasets` interceptor. The (possibly modified) response returned by + `post_list_datasets` will be passed to + `post_list_datasets_with_metadata`. + """ + return response, metadata + def pre_update_dataset_metadata( self, request: maps_platform_datasets.UpdateDatasetMetadataRequest, @@ -256,12 +354,35 @@ def post_update_dataset_metadata( ) -> gmm_dataset.Dataset: """Post-rpc interceptor for update_dataset_metadata - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_dataset_metadata_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MapsPlatformDatasets server but before - it is returned to user code. + it is returned to user code. This `post_update_dataset_metadata` interceptor runs + before the `post_update_dataset_metadata_with_metadata` interceptor. """ return response + def post_update_dataset_metadata_with_metadata( + self, + response: gmm_dataset.Dataset, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gmm_dataset.Dataset, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_dataset_metadata + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MapsPlatformDatasets server but before it is returned to user code. + + We recommend only using this `post_update_dataset_metadata_with_metadata` + interceptor in new development instead of the `post_update_dataset_metadata` interceptor. + When both interceptors are used, this `post_update_dataset_metadata_with_metadata` interceptor runs after the + `post_update_dataset_metadata` interceptor. The (possibly modified) response returned by + `post_update_dataset_metadata` will be passed to + `post_update_dataset_metadata_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class MapsPlatformDatasetsRestStub: @@ -475,6 +596,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_dataset(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_dataset_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -730,6 +855,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_fetch_dataset_errors(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_fetch_dataset_errors_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -877,6 +1006,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_dataset(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_dataset_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1019,6 +1152,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_datasets(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_datasets_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1175,6 +1312,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_dataset_metadata(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_dataset_metadata_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-maps-mapsplatformdatasets/noxfile.py b/packages/google-maps-mapsplatformdatasets/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-maps-mapsplatformdatasets/noxfile.py +++ b/packages/google-maps-mapsplatformdatasets/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json b/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json index 18408371c629..efd05ec97721 100644 --- a/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json +++ b/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-mapsplatformdatasets", - "version": "0.4.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-maps-mapsplatformdatasets/tests/unit/gapic/mapsplatformdatasets_v1/test_maps_platform_datasets.py b/packages/google-maps-mapsplatformdatasets/tests/unit/gapic/mapsplatformdatasets_v1/test_maps_platform_datasets.py index 60039a8110ef..5b330d921df2 100644 --- a/packages/google-maps-mapsplatformdatasets/tests/unit/gapic/mapsplatformdatasets_v1/test_maps_platform_datasets.py +++ b/packages/google-maps-mapsplatformdatasets/tests/unit/gapic/mapsplatformdatasets_v1/test_maps_platform_datasets.py @@ -66,6 +66,13 @@ from google.maps.mapsplatformdatasets_v1.types import dataset as gmm_dataset from google.maps.mapsplatformdatasets_v1.types import maps_platform_datasets +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = MapsPlatformDatasetsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = MapsPlatformDatasetsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5405,10 +5455,14 @@ def test_create_dataset_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "post_create_dataset" ) as post, mock.patch.object( + transports.MapsPlatformDatasetsRestInterceptor, + "post_create_dataset_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "pre_create_dataset" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = maps_platform_datasets.CreateDatasetRequest.pb( maps_platform_datasets.CreateDatasetRequest() ) @@ -5432,6 +5486,7 @@ def test_create_dataset_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gmm_dataset.Dataset() + post_with_metadata.return_value = gmm_dataset.Dataset(), metadata client.create_dataset( request, @@ -5443,6 +5498,7 @@ def test_create_dataset_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_dataset_metadata_rest_bad_request( @@ -5620,10 +5676,14 @@ def test_update_dataset_metadata_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "post_update_dataset_metadata" ) as post, mock.patch.object( + transports.MapsPlatformDatasetsRestInterceptor, + "post_update_dataset_metadata_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "pre_update_dataset_metadata" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = maps_platform_datasets.UpdateDatasetMetadataRequest.pb( maps_platform_datasets.UpdateDatasetMetadataRequest() ) @@ -5647,6 +5707,7 @@ def test_update_dataset_metadata_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gmm_dataset.Dataset() + post_with_metadata.return_value = gmm_dataset.Dataset(), metadata client.update_dataset_metadata( request, @@ -5658,6 +5719,7 @@ def test_update_dataset_metadata_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_dataset_rest_bad_request( @@ -5752,10 +5814,13 @@ def test_get_dataset_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "post_get_dataset" ) as post, mock.patch.object( + transports.MapsPlatformDatasetsRestInterceptor, "post_get_dataset_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "pre_get_dataset" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = maps_platform_datasets.GetDatasetRequest.pb( maps_platform_datasets.GetDatasetRequest() ) @@ -5779,6 +5844,7 @@ def test_get_dataset_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = dataset.Dataset() + post_with_metadata.return_value = dataset.Dataset(), metadata client.get_dataset( request, @@ -5790,6 +5856,7 @@ def test_get_dataset_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_fetch_dataset_errors_rest_bad_request( @@ -5876,10 +5943,14 @@ def test_fetch_dataset_errors_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "post_fetch_dataset_errors" ) as post, mock.patch.object( + transports.MapsPlatformDatasetsRestInterceptor, + "post_fetch_dataset_errors_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "pre_fetch_dataset_errors" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = maps_platform_datasets.FetchDatasetErrorsRequest.pb( maps_platform_datasets.FetchDatasetErrorsRequest() ) @@ -5905,6 +5976,10 @@ def test_fetch_dataset_errors_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = maps_platform_datasets.FetchDatasetErrorsResponse() + post_with_metadata.return_value = ( + maps_platform_datasets.FetchDatasetErrorsResponse(), + metadata, + ) client.fetch_dataset_errors( request, @@ -5916,6 +5991,7 @@ def test_fetch_dataset_errors_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_datasets_rest_bad_request( @@ -6000,10 +6076,14 @@ def test_list_datasets_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "post_list_datasets" ) as post, mock.patch.object( + transports.MapsPlatformDatasetsRestInterceptor, + "post_list_datasets_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MapsPlatformDatasetsRestInterceptor, "pre_list_datasets" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = maps_platform_datasets.ListDatasetsRequest.pb( maps_platform_datasets.ListDatasetsRequest() ) @@ -6029,6 +6109,10 @@ def test_list_datasets_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = maps_platform_datasets.ListDatasetsResponse() + post_with_metadata.return_value = ( + maps_platform_datasets.ListDatasetsResponse(), + metadata, + ) client.list_datasets( request, @@ -6040,6 +6124,7 @@ def test_list_datasets_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_dataset_rest_bad_request( diff --git a/packages/google-maps-routeoptimization/README.rst b/packages/google-maps-routeoptimization/README.rst index 8b1300294995..8b6ede3a81f7 100644 --- a/packages/google-maps-routeoptimization/README.rst +++ b/packages/google-maps-routeoptimization/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Route Optimization API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Route Optimization API.: https://developers.google.com/maps/documentation/route-optimization -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/client.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/client.py index 6d57e2ba7255..b0635872003e 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/client.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -488,6 +490,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -991,16 +1020,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/transports/rest.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/transports/rest.py index c5c585833fc9..ca3eb0c33435 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/transports/rest.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/services/route_optimization/transports/rest.py @@ -111,12 +111,35 @@ def post_batch_optimize_tours( ) -> operations_pb2.Operation: """Post-rpc interceptor for batch_optimize_tours - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_optimize_tours_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RouteOptimization server but before - it is returned to user code. + it is returned to user code. This `post_batch_optimize_tours` interceptor runs + before the `post_batch_optimize_tours_with_metadata` interceptor. """ return response + def post_batch_optimize_tours_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for batch_optimize_tours + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RouteOptimization server but before it is returned to user code. + + We recommend only using this `post_batch_optimize_tours_with_metadata` + interceptor in new development instead of the `post_batch_optimize_tours` interceptor. + When both interceptors are used, this `post_batch_optimize_tours_with_metadata` interceptor runs after the + `post_batch_optimize_tours` interceptor. The (possibly modified) response returned by + `post_batch_optimize_tours` will be passed to + `post_batch_optimize_tours_with_metadata`. + """ + return response, metadata + def pre_optimize_tours( self, request: route_optimization_service.OptimizeToursRequest, @@ -137,12 +160,38 @@ def post_optimize_tours( ) -> route_optimization_service.OptimizeToursResponse: """Post-rpc interceptor for optimize_tours - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_optimize_tours_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RouteOptimization server but before - it is returned to user code. + it is returned to user code. This `post_optimize_tours` interceptor runs + before the `post_optimize_tours_with_metadata` interceptor. """ return response + def post_optimize_tours_with_metadata( + self, + response: route_optimization_service.OptimizeToursResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + route_optimization_service.OptimizeToursResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for optimize_tours + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RouteOptimization server but before it is returned to user code. + + We recommend only using this `post_optimize_tours_with_metadata` + interceptor in new development instead of the `post_optimize_tours` interceptor. + When both interceptors are used, this `post_optimize_tours_with_metadata` interceptor runs after the + `post_optimize_tours` interceptor. The (possibly modified) response returned by + `post_optimize_tours` will be passed to + `post_optimize_tours_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -445,6 +494,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_optimize_tours(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_batch_optimize_tours_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -600,6 +653,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_optimize_tours(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_optimize_tours_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-maps-routeoptimization/noxfile.py b/packages/google-maps-routeoptimization/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-maps-routeoptimization/noxfile.py +++ b/packages/google-maps-routeoptimization/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json b/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json index fcc409ee621b..fcfcf65d2f4f 100644 --- a/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json +++ b/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-routeoptimization", - "version": "0.1.7" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-maps-routeoptimization/tests/unit/gapic/routeoptimization_v1/test_route_optimization.py b/packages/google-maps-routeoptimization/tests/unit/gapic/routeoptimization_v1/test_route_optimization.py index c8817288cd0e..a756f3d0792e 100644 --- a/packages/google-maps-routeoptimization/tests/unit/gapic/routeoptimization_v1/test_route_optimization.py +++ b/packages/google-maps-routeoptimization/tests/unit/gapic/routeoptimization_v1/test_route_optimization.py @@ -72,6 +72,13 @@ ) from google.maps.routeoptimization_v1.types import route_optimization_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RouteOptimizationClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RouteOptimizationClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2178,10 +2228,13 @@ def test_optimize_tours_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RouteOptimizationRestInterceptor, "post_optimize_tours" ) as post, mock.patch.object( + transports.RouteOptimizationRestInterceptor, "post_optimize_tours_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RouteOptimizationRestInterceptor, "pre_optimize_tours" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = route_optimization_service.OptimizeToursRequest.pb( route_optimization_service.OptimizeToursRequest() ) @@ -2207,6 +2260,10 @@ def test_optimize_tours_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = route_optimization_service.OptimizeToursResponse() + post_with_metadata.return_value = ( + route_optimization_service.OptimizeToursResponse(), + metadata, + ) client.optimize_tours( request, @@ -2218,6 +2275,7 @@ def test_optimize_tours_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_optimize_tours_rest_bad_request( @@ -2298,10 +2356,14 @@ def test_batch_optimize_tours_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RouteOptimizationRestInterceptor, "post_batch_optimize_tours" ) as post, mock.patch.object( + transports.RouteOptimizationRestInterceptor, + "post_batch_optimize_tours_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RouteOptimizationRestInterceptor, "pre_batch_optimize_tours" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = route_optimization_service.BatchOptimizeToursRequest.pb( route_optimization_service.BatchOptimizeToursRequest() ) @@ -2325,6 +2387,7 @@ def test_batch_optimize_tours_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.batch_optimize_tours( request, @@ -2336,6 +2399,7 @@ def test_batch_optimize_tours_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-maps-routing/README.rst b/packages/google-maps-routing/README.rst index 60b757b272f2..365be319643d 100644 --- a/packages/google-maps-routing/README.rst +++ b/packages/google-maps-routing/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Maps Routing.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Maps Routing.: https://mapsplatform.google.com/maps-products/#routes-section -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-maps-routing/google/maps/routing/gapic_version.py b/packages/google-maps-routing/google/maps/routing/gapic_version.py index b72badcc1eca..558c8aab67c5 100644 --- a/packages/google-maps-routing/google/maps/routing/gapic_version.py +++ b/packages/google-maps-routing/google/maps/routing/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py b/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py index b72badcc1eca..558c8aab67c5 100644 --- a/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py +++ b/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-routing/google/maps/routing_v2/services/routes/client.py b/packages/google-maps-routing/google/maps/routing_v2/services/routes/client.py index 71cdfe6b5391..3d70cca35f81 100644 --- a/packages/google-maps-routing/google/maps/routing_v2/services/routes/client.py +++ b/packages/google-maps-routing/google/maps/routing_v2/services/routes/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -468,6 +470,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-maps-routing/google/maps/routing_v2/services/routes/transports/rest.py b/packages/google-maps-routing/google/maps/routing_v2/services/routes/transports/rest.py index e3209c8e05df..de94b9a2126b 100644 --- a/packages/google-maps-routing/google/maps/routing_v2/services/routes/transports/rest.py +++ b/packages/google-maps-routing/google/maps/routing_v2/services/routes/transports/rest.py @@ -110,12 +110,37 @@ def post_compute_route_matrix( ) -> rest_streaming.ResponseIterator: """Post-rpc interceptor for compute_route_matrix - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_compute_route_matrix_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Routes server but before - it is returned to user code. + it is returned to user code. This `post_compute_route_matrix` interceptor runs + before the `post_compute_route_matrix_with_metadata` interceptor. """ return response + def post_compute_route_matrix_with_metadata( + self, + response: rest_streaming.ResponseIterator, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + rest_streaming.ResponseIterator, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for compute_route_matrix + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Routes server but before it is returned to user code. + + We recommend only using this `post_compute_route_matrix_with_metadata` + interceptor in new development instead of the `post_compute_route_matrix` interceptor. + When both interceptors are used, this `post_compute_route_matrix_with_metadata` interceptor runs after the + `post_compute_route_matrix` interceptor. The (possibly modified) response returned by + `post_compute_route_matrix` will be passed to + `post_compute_route_matrix_with_metadata`. + """ + return response, metadata + def pre_compute_routes( self, request: routes_service.ComputeRoutesRequest, @@ -135,12 +160,37 @@ def post_compute_routes( ) -> routes_service.ComputeRoutesResponse: """Post-rpc interceptor for compute_routes - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_compute_routes_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Routes server but before - it is returned to user code. + it is returned to user code. This `post_compute_routes` interceptor runs + before the `post_compute_routes_with_metadata` interceptor. """ return response + def post_compute_routes_with_metadata( + self, + response: routes_service.ComputeRoutesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + routes_service.ComputeRoutesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for compute_routes + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Routes server but before it is returned to user code. + + We recommend only using this `post_compute_routes_with_metadata` + interceptor in new development instead of the `post_compute_routes` interceptor. + When both interceptors are used, this `post_compute_routes_with_metadata` interceptor runs after the + `post_compute_routes` interceptor. The (possibly modified) response returned by + `post_compute_routes` will be passed to + `post_compute_routes_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class RoutesRestStub: @@ -361,6 +411,10 @@ def __call__( ) resp = self._interceptor.post_compute_route_matrix(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_compute_route_matrix_with_metadata( + resp, response_metadata + ) return resp class _ComputeRoutes(_BaseRoutesRestTransport._BaseComputeRoutes, RoutesRestStub): @@ -488,6 +542,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_compute_routes(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_compute_routes_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-maps-routing/noxfile.py b/packages/google-maps-routing/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-maps-routing/noxfile.py +++ b/packages/google-maps-routing/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json b/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json index 6a748ce34a14..ebb0fa3e0c00 100644 --- a/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json +++ b/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-routing", - "version": "0.6.13" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-maps-routing/tests/unit/gapic/routing_v2/test_routes.py b/packages/google-maps-routing/tests/unit/gapic/routing_v2/test_routes.py index 133a7dcd7615..e5d1a561a382 100644 --- a/packages/google-maps-routing/tests/unit/gapic/routing_v2/test_routes.py +++ b/packages/google-maps-routing/tests/unit/gapic/routing_v2/test_routes.py @@ -81,6 +81,13 @@ waypoint, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -303,6 +310,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RoutesClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RoutesClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1935,10 +1985,13 @@ def test_compute_routes_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RoutesRestInterceptor, "post_compute_routes" ) as post, mock.patch.object( + transports.RoutesRestInterceptor, "post_compute_routes_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RoutesRestInterceptor, "pre_compute_routes" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = routes_service.ComputeRoutesRequest.pb( routes_service.ComputeRoutesRequest() ) @@ -1964,6 +2017,10 @@ def test_compute_routes_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = routes_service.ComputeRoutesResponse() + post_with_metadata.return_value = ( + routes_service.ComputeRoutesResponse(), + metadata, + ) client.compute_routes( request, @@ -1975,6 +2032,7 @@ def test_compute_routes_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_compute_route_matrix_rest_bad_request( @@ -2067,10 +2125,13 @@ def test_compute_route_matrix_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RoutesRestInterceptor, "post_compute_route_matrix" ) as post, mock.patch.object( + transports.RoutesRestInterceptor, "post_compute_route_matrix_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RoutesRestInterceptor, "pre_compute_route_matrix" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = routes_service.ComputeRouteMatrixRequest.pb( routes_service.ComputeRouteMatrixRequest() ) @@ -2096,6 +2157,7 @@ def test_compute_route_matrix_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = routes_service.RouteMatrixElement() + post_with_metadata.return_value = routes_service.RouteMatrixElement(), metadata client.compute_route_matrix( request, @@ -2107,6 +2169,7 @@ def test_compute_route_matrix_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-maps-solar/README.rst b/packages/google-maps-solar/README.rst index fd9724f9887b..22fe6c4001b0 100644 --- a/packages/google-maps-solar/README.rst +++ b/packages/google-maps-solar/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Solar API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Solar API.: https://developers.google.com/maps/documentation/solar/overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-maps-solar/google/maps/solar/gapic_version.py b/packages/google-maps-solar/google/maps/solar/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-maps-solar/google/maps/solar/gapic_version.py +++ b/packages/google-maps-solar/google/maps/solar/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py b/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py +++ b/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-maps-solar/google/maps/solar_v1/services/solar/client.py b/packages/google-maps-solar/google/maps/solar_v1/services/solar/client.py index 48fcc5a94162..98b72175358f 100644 --- a/packages/google-maps-solar/google/maps/solar_v1/services/solar/client.py +++ b/packages/google-maps-solar/google/maps/solar_v1/services/solar/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -464,6 +466,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-maps-solar/google/maps/solar_v1/services/solar/transports/rest.py b/packages/google-maps-solar/google/maps/solar_v1/services/solar/transports/rest.py index 876ab8b0ffcd..fefe71e4ce00 100644 --- a/packages/google-maps-solar/google/maps/solar_v1/services/solar/transports/rest.py +++ b/packages/google-maps-solar/google/maps/solar_v1/services/solar/transports/rest.py @@ -119,12 +119,35 @@ def post_find_closest_building_insights( ) -> solar_service.BuildingInsights: """Post-rpc interceptor for find_closest_building_insights - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_find_closest_building_insights_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Solar server but before - it is returned to user code. + it is returned to user code. This `post_find_closest_building_insights` interceptor runs + before the `post_find_closest_building_insights_with_metadata` interceptor. """ return response + def post_find_closest_building_insights_with_metadata( + self, + response: solar_service.BuildingInsights, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[solar_service.BuildingInsights, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for find_closest_building_insights + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Solar server but before it is returned to user code. + + We recommend only using this `post_find_closest_building_insights_with_metadata` + interceptor in new development instead of the `post_find_closest_building_insights` interceptor. + When both interceptors are used, this `post_find_closest_building_insights_with_metadata` interceptor runs after the + `post_find_closest_building_insights` interceptor. The (possibly modified) response returned by + `post_find_closest_building_insights` will be passed to + `post_find_closest_building_insights_with_metadata`. + """ + return response, metadata + def pre_get_data_layers( self, request: solar_service.GetDataLayersRequest, @@ -144,12 +167,35 @@ def post_get_data_layers( ) -> solar_service.DataLayers: """Post-rpc interceptor for get_data_layers - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_data_layers_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Solar server but before - it is returned to user code. + it is returned to user code. This `post_get_data_layers` interceptor runs + before the `post_get_data_layers_with_metadata` interceptor. """ return response + def post_get_data_layers_with_metadata( + self, + response: solar_service.DataLayers, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[solar_service.DataLayers, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_data_layers + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Solar server but before it is returned to user code. + + We recommend only using this `post_get_data_layers_with_metadata` + interceptor in new development instead of the `post_get_data_layers` interceptor. + When both interceptors are used, this `post_get_data_layers_with_metadata` interceptor runs after the + `post_get_data_layers` interceptor. The (possibly modified) response returned by + `post_get_data_layers` will be passed to + `post_get_data_layers_with_metadata`. + """ + return response, metadata + def pre_get_geo_tiff( self, request: solar_service.GetGeoTiffRequest, @@ -169,12 +215,35 @@ def post_get_geo_tiff( ) -> httpbody_pb2.HttpBody: """Post-rpc interceptor for get_geo_tiff - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_geo_tiff_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Solar server but before - it is returned to user code. + it is returned to user code. This `post_get_geo_tiff` interceptor runs + before the `post_get_geo_tiff_with_metadata` interceptor. """ return response + def post_get_geo_tiff_with_metadata( + self, + response: httpbody_pb2.HttpBody, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[httpbody_pb2.HttpBody, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_geo_tiff + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Solar server but before it is returned to user code. + + We recommend only using this `post_get_geo_tiff_with_metadata` + interceptor in new development instead of the `post_get_geo_tiff` interceptor. + When both interceptors are used, this `post_get_geo_tiff_with_metadata` interceptor runs after the + `post_get_geo_tiff` interceptor. The (possibly modified) response returned by + `post_get_geo_tiff` will be passed to + `post_get_geo_tiff_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class SolarRestStub: @@ -387,6 +456,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_find_closest_building_insights(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_find_closest_building_insights_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -541,6 +617,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_data_layers(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_data_layers_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -730,6 +810,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_geo_tiff(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_geo_tiff_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-maps-solar/noxfile.py b/packages/google-maps-solar/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-maps-solar/noxfile.py +++ b/packages/google-maps-solar/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json b/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json index 8ee9a923f55d..b0cd14fdb324 100644 --- a/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json +++ b/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-solar", - "version": "0.1.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-maps-solar/tests/unit/gapic/solar_v1/test_solar.py b/packages/google-maps-solar/tests/unit/gapic/solar_v1/test_solar.py index 3771905a07a0..5efaab6a41a8 100644 --- a/packages/google-maps-solar/tests/unit/gapic/solar_v1/test_solar.py +++ b/packages/google-maps-solar/tests/unit/gapic/solar_v1/test_solar.py @@ -63,6 +63,13 @@ ) from google.maps.solar_v1.types import solar_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -281,6 +288,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = SolarClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = SolarClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2385,10 +2435,14 @@ def test_find_closest_building_insights_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SolarRestInterceptor, "post_find_closest_building_insights" ) as post, mock.patch.object( + transports.SolarRestInterceptor, + "post_find_closest_building_insights_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.SolarRestInterceptor, "pre_find_closest_building_insights" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = solar_service.FindClosestBuildingInsightsRequest.pb( solar_service.FindClosestBuildingInsightsRequest() ) @@ -2414,6 +2468,7 @@ def test_find_closest_building_insights_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = solar_service.BuildingInsights() + post_with_metadata.return_value = solar_service.BuildingInsights(), metadata client.find_closest_building_insights( request, @@ -2425,6 +2480,7 @@ def test_find_closest_building_insights_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_data_layers_rest_bad_request( @@ -2519,10 +2575,13 @@ def test_get_data_layers_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SolarRestInterceptor, "post_get_data_layers" ) as post, mock.patch.object( + transports.SolarRestInterceptor, "post_get_data_layers_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SolarRestInterceptor, "pre_get_data_layers" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = solar_service.GetDataLayersRequest.pb( solar_service.GetDataLayersRequest() ) @@ -2546,6 +2605,7 @@ def test_get_data_layers_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = solar_service.DataLayers() + post_with_metadata.return_value = solar_service.DataLayers(), metadata client.get_data_layers( request, @@ -2557,6 +2617,7 @@ def test_get_data_layers_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_geo_tiff_rest_bad_request(request_type=solar_service.GetGeoTiffRequest): @@ -2636,10 +2697,13 @@ def test_get_geo_tiff_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SolarRestInterceptor, "post_get_geo_tiff" ) as post, mock.patch.object( + transports.SolarRestInterceptor, "post_get_geo_tiff_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SolarRestInterceptor, "pre_get_geo_tiff" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = solar_service.GetGeoTiffRequest.pb( solar_service.GetGeoTiffRequest() ) @@ -2663,6 +2727,7 @@ def test_get_geo_tiff_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = httpbody_pb2.HttpBody() + post_with_metadata.return_value = httpbody_pb2.HttpBody(), metadata client.get_geo_tiff( request, @@ -2674,6 +2739,7 @@ def test_get_geo_tiff_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-css/README.rst b/packages/google-shopping-css/README.rst index 72ebc30f4cdb..126ac2de2699 100644 --- a/packages/google-shopping-css/README.rst +++ b/packages/google-shopping-css/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the CSS API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the CSS API.: https://developers.google.com/comparison-shopping-services/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-css/google/shopping/css/gapic_version.py b/packages/google-shopping-css/google/shopping/css/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-css/google/shopping/css/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py index 92ce045e0ae2..2d9fb2f02540 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -479,6 +481,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py index 40e81c19ee91..26ea194ec64e 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py @@ -123,12 +123,35 @@ def post_create_account_label( ) -> accounts_labels.AccountLabel: """Post-rpc interceptor for create_account_label - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_account_label_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountLabelsService server but before - it is returned to user code. + it is returned to user code. This `post_create_account_label` interceptor runs + before the `post_create_account_label_with_metadata` interceptor. """ return response + def post_create_account_label_with_metadata( + self, + response: accounts_labels.AccountLabel, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts_labels.AccountLabel, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_account_label + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountLabelsService server but before it is returned to user code. + + We recommend only using this `post_create_account_label_with_metadata` + interceptor in new development instead of the `post_create_account_label` interceptor. + When both interceptors are used, this `post_create_account_label_with_metadata` interceptor runs after the + `post_create_account_label` interceptor. The (possibly modified) response returned by + `post_create_account_label` will be passed to + `post_create_account_label_with_metadata`. + """ + return response, metadata + def pre_delete_account_label( self, request: accounts_labels.DeleteAccountLabelRequest, @@ -164,12 +187,38 @@ def post_list_account_labels( ) -> accounts_labels.ListAccountLabelsResponse: """Post-rpc interceptor for list_account_labels - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_account_labels_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountLabelsService server but before - it is returned to user code. + it is returned to user code. This `post_list_account_labels` interceptor runs + before the `post_list_account_labels_with_metadata` interceptor. """ return response + def post_list_account_labels_with_metadata( + self, + response: accounts_labels.ListAccountLabelsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts_labels.ListAccountLabelsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_account_labels + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountLabelsService server but before it is returned to user code. + + We recommend only using this `post_list_account_labels_with_metadata` + interceptor in new development instead of the `post_list_account_labels` interceptor. + When both interceptors are used, this `post_list_account_labels_with_metadata` interceptor runs after the + `post_list_account_labels` interceptor. The (possibly modified) response returned by + `post_list_account_labels` will be passed to + `post_list_account_labels_with_metadata`. + """ + return response, metadata + def pre_update_account_label( self, request: accounts_labels.UpdateAccountLabelRequest, @@ -190,12 +239,35 @@ def post_update_account_label( ) -> accounts_labels.AccountLabel: """Post-rpc interceptor for update_account_label - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_account_label_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountLabelsService server but before - it is returned to user code. + it is returned to user code. This `post_update_account_label` interceptor runs + before the `post_update_account_label_with_metadata` interceptor. """ return response + def post_update_account_label_with_metadata( + self, + response: accounts_labels.AccountLabel, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts_labels.AccountLabel, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_account_label + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountLabelsService server but before it is returned to user code. + + We recommend only using this `post_update_account_label_with_metadata` + interceptor in new development instead of the `post_update_account_label` interceptor. + When both interceptors are used, this `post_update_account_label_with_metadata` interceptor runs after the + `post_update_account_label` interceptor. The (possibly modified) response returned by + `post_update_account_label` will be passed to + `post_update_account_label_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AccountLabelsServiceRestStub: @@ -414,6 +486,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_account_label(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_account_label_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -671,6 +747,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_account_labels(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_account_labels_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -826,6 +906,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_account_label(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_account_label_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py index 607097515615..26d05be4a316 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -477,6 +479,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py index 9a085333d5f3..f4eb6fa83e49 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py @@ -113,12 +113,35 @@ def pre_get_account( def post_get_account(self, response: accounts.Account) -> accounts.Account: """Post-rpc interceptor for get_account - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_account_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_get_account` interceptor runs + before the `post_get_account_with_metadata` interceptor. """ return response + def post_get_account_with_metadata( + self, + response: accounts.Account, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.Account, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_account + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_get_account_with_metadata` + interceptor in new development instead of the `post_get_account` interceptor. + When both interceptors are used, this `post_get_account_with_metadata` interceptor runs after the + `post_get_account` interceptor. The (possibly modified) response returned by + `post_get_account` will be passed to + `post_get_account_with_metadata`. + """ + return response, metadata + def pre_list_child_accounts( self, request: accounts.ListChildAccountsRequest, @@ -138,12 +161,37 @@ def post_list_child_accounts( ) -> accounts.ListChildAccountsResponse: """Post-rpc interceptor for list_child_accounts - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_child_accounts_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_list_child_accounts` interceptor runs + before the `post_list_child_accounts_with_metadata` interceptor. """ return response + def post_list_child_accounts_with_metadata( + self, + response: accounts.ListChildAccountsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts.ListChildAccountsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_child_accounts + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_list_child_accounts_with_metadata` + interceptor in new development instead of the `post_list_child_accounts` interceptor. + When both interceptors are used, this `post_list_child_accounts_with_metadata` interceptor runs after the + `post_list_child_accounts` interceptor. The (possibly modified) response returned by + `post_list_child_accounts` will be passed to + `post_list_child_accounts_with_metadata`. + """ + return response, metadata + def pre_update_labels( self, request: accounts.UpdateAccountLabelsRequest, @@ -161,12 +209,35 @@ def pre_update_labels( def post_update_labels(self, response: accounts.Account) -> accounts.Account: """Post-rpc interceptor for update_labels - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_labels_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_update_labels` interceptor runs + before the `post_update_labels_with_metadata` interceptor. """ return response + def post_update_labels_with_metadata( + self, + response: accounts.Account, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.Account, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_labels + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_update_labels_with_metadata` + interceptor in new development instead of the `post_update_labels` interceptor. + When both interceptors are used, this `post_update_labels_with_metadata` interceptor runs after the + `post_update_labels` interceptor. The (possibly modified) response returned by + `post_update_labels` will be passed to + `post_update_labels_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AccountsServiceRestStub: @@ -371,6 +442,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_account(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_account_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -515,6 +590,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_child_accounts(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_child_accounts_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -663,6 +742,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_labels(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_labels_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py index 9c064da000bd..94a15b31ee80 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -489,6 +491,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py index 2d43d49e302c..0a9be1af5cdc 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py @@ -130,12 +130,37 @@ def post_insert_css_product_input( ) -> css_product_inputs.CssProductInput: """Post-rpc interceptor for insert_css_product_input - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_css_product_input_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CssProductInputsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_css_product_input` interceptor runs + before the `post_insert_css_product_input_with_metadata` interceptor. """ return response + def post_insert_css_product_input_with_metadata( + self, + response: css_product_inputs.CssProductInput, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + css_product_inputs.CssProductInput, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for insert_css_product_input + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CssProductInputsService server but before it is returned to user code. + + We recommend only using this `post_insert_css_product_input_with_metadata` + interceptor in new development instead of the `post_insert_css_product_input` interceptor. + When both interceptors are used, this `post_insert_css_product_input_with_metadata` interceptor runs after the + `post_insert_css_product_input` interceptor. The (possibly modified) response returned by + `post_insert_css_product_input` will be passed to + `post_insert_css_product_input_with_metadata`. + """ + return response, metadata + def pre_update_css_product_input( self, request: css_product_inputs.UpdateCssProductInputRequest, @@ -156,12 +181,37 @@ def post_update_css_product_input( ) -> css_product_inputs.CssProductInput: """Post-rpc interceptor for update_css_product_input - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_css_product_input_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CssProductInputsService server but before - it is returned to user code. + it is returned to user code. This `post_update_css_product_input` interceptor runs + before the `post_update_css_product_input_with_metadata` interceptor. """ return response + def post_update_css_product_input_with_metadata( + self, + response: css_product_inputs.CssProductInput, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + css_product_inputs.CssProductInput, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_css_product_input + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CssProductInputsService server but before it is returned to user code. + + We recommend only using this `post_update_css_product_input_with_metadata` + interceptor in new development instead of the `post_update_css_product_input` interceptor. + When both interceptors are used, this `post_update_css_product_input_with_metadata` interceptor runs after the + `post_update_css_product_input` interceptor. The (possibly modified) response returned by + `post_update_css_product_input` will be passed to + `post_update_css_product_input_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CssProductInputsServiceRestStub: @@ -492,6 +542,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_css_product_input(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_css_product_input_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -649,6 +703,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_css_product_input(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_css_product_input_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py index 735ab6437f2d..d73269dc4c16 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -485,6 +487,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py index 657152f7dc0f..3a4a3f250edb 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py @@ -109,12 +109,35 @@ def post_get_css_product( ) -> css_products.CssProduct: """Post-rpc interceptor for get_css_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_css_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CssProductsService server but before - it is returned to user code. + it is returned to user code. This `post_get_css_product` interceptor runs + before the `post_get_css_product_with_metadata` interceptor. """ return response + def post_get_css_product_with_metadata( + self, + response: css_products.CssProduct, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[css_products.CssProduct, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_css_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CssProductsService server but before it is returned to user code. + + We recommend only using this `post_get_css_product_with_metadata` + interceptor in new development instead of the `post_get_css_product` interceptor. + When both interceptors are used, this `post_get_css_product_with_metadata` interceptor runs after the + `post_get_css_product` interceptor. The (possibly modified) response returned by + `post_get_css_product` will be passed to + `post_get_css_product_with_metadata`. + """ + return response, metadata + def pre_list_css_products( self, request: css_products.ListCssProductsRequest, @@ -134,12 +157,37 @@ def post_list_css_products( ) -> css_products.ListCssProductsResponse: """Post-rpc interceptor for list_css_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_css_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CssProductsService server but before - it is returned to user code. + it is returned to user code. This `post_list_css_products` interceptor runs + before the `post_list_css_products_with_metadata` interceptor. """ return response + def post_list_css_products_with_metadata( + self, + response: css_products.ListCssProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + css_products.ListCssProductsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_css_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CssProductsService server but before it is returned to user code. + + We recommend only using this `post_list_css_products_with_metadata` + interceptor in new development instead of the `post_list_css_products` interceptor. + When both interceptors are used, this `post_list_css_products_with_metadata` interceptor runs after the + `post_list_css_products` interceptor. The (possibly modified) response returned by + `post_list_css_products` will be passed to + `post_list_css_products_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CssProductsServiceRestStub: @@ -346,6 +394,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_css_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_css_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -492,6 +544,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_css_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_css_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-css/noxfile.py b/packages/google-shopping-css/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-css/noxfile.py +++ b/packages/google-shopping-css/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json index d04baa6c9762..6cbd0ab66db5 100644 --- a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json +++ b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-css", - "version": "0.1.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py index bdbd908f0492..4acbf0725887 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py @@ -60,6 +60,13 @@ ) from google.shopping.css_v1.types import accounts_labels +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -333,6 +340,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AccountLabelsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AccountLabelsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3950,10 +4000,14 @@ def test_list_account_labels_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "post_list_account_labels" ) as post, mock.patch.object( + transports.AccountLabelsServiceRestInterceptor, + "post_list_account_labels_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "pre_list_account_labels" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts_labels.ListAccountLabelsRequest.pb( accounts_labels.ListAccountLabelsRequest() ) @@ -3979,6 +4033,10 @@ def test_list_account_labels_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts_labels.ListAccountLabelsResponse() + post_with_metadata.return_value = ( + accounts_labels.ListAccountLabelsResponse(), + metadata, + ) client.list_account_labels( request, @@ -3990,6 +4048,7 @@ def test_list_account_labels_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_account_label_rest_bad_request( @@ -4159,10 +4218,14 @@ def test_create_account_label_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "post_create_account_label" ) as post, mock.patch.object( + transports.AccountLabelsServiceRestInterceptor, + "post_create_account_label_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "pre_create_account_label" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts_labels.CreateAccountLabelRequest.pb( accounts_labels.CreateAccountLabelRequest() ) @@ -4188,6 +4251,7 @@ def test_create_account_label_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts_labels.AccountLabel() + post_with_metadata.return_value = accounts_labels.AccountLabel(), metadata client.create_account_label( request, @@ -4199,6 +4263,7 @@ def test_create_account_label_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_account_label_rest_bad_request( @@ -4368,10 +4433,14 @@ def test_update_account_label_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "post_update_account_label" ) as post, mock.patch.object( + transports.AccountLabelsServiceRestInterceptor, + "post_update_account_label_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountLabelsServiceRestInterceptor, "pre_update_account_label" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts_labels.UpdateAccountLabelRequest.pb( accounts_labels.UpdateAccountLabelRequest() ) @@ -4397,6 +4466,7 @@ def test_update_account_label_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts_labels.AccountLabel() + post_with_metadata.return_value = accounts_labels.AccountLabel(), metadata client.update_account_label( request, @@ -4408,6 +4478,7 @@ def test_update_account_label_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_account_label_rest_bad_request( diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py index bb6835d5bc1c..12b9afe8fe22 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py @@ -60,6 +60,13 @@ ) from google.shopping.css_v1.types import accounts +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -318,6 +325,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AccountsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AccountsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3316,10 +3366,14 @@ def test_list_child_accounts_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_list_child_accounts" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, + "post_list_child_accounts_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_list_child_accounts" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.ListChildAccountsRequest.pb( accounts.ListChildAccountsRequest() ) @@ -3345,6 +3399,7 @@ def test_list_child_accounts_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.ListChildAccountsResponse() + post_with_metadata.return_value = accounts.ListChildAccountsResponse(), metadata client.list_child_accounts( request, @@ -3356,6 +3411,7 @@ def test_list_child_accounts_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_account_rest_bad_request(request_type=accounts.GetAccountRequest): @@ -3452,10 +3508,13 @@ def test_get_account_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_get_account" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, "post_get_account_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_get_account" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.GetAccountRequest.pb(accounts.GetAccountRequest()) transcode.return_value = { "method": "post", @@ -3477,6 +3536,7 @@ def test_get_account_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.Account() + post_with_metadata.return_value = accounts.Account(), metadata client.get_account( request, @@ -3488,6 +3548,7 @@ def test_get_account_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_labels_rest_bad_request( @@ -3586,10 +3647,13 @@ def test_update_labels_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_update_labels" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, "post_update_labels_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_update_labels" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.UpdateAccountLabelsRequest.pb( accounts.UpdateAccountLabelsRequest() ) @@ -3613,6 +3677,7 @@ def test_update_labels_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.Account() + post_with_metadata.return_value = accounts.Account(), metadata client.update_labels( request, @@ -3624,6 +3689,7 @@ def test_update_labels_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py index 9b3c3004de34..490c6e6c6979 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py @@ -62,6 +62,13 @@ ) from google.shopping.css_v1.types import css_product_common, css_product_inputs +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CssProductInputsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CssProductInputsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3140,11 +3190,15 @@ def test_insert_css_product_input_rest_interceptors(null_interceptor): transports.CssProductInputsServiceRestInterceptor, "post_insert_css_product_input", ) as post, mock.patch.object( + transports.CssProductInputsServiceRestInterceptor, + "post_insert_css_product_input_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CssProductInputsServiceRestInterceptor, "pre_insert_css_product_input", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = css_product_inputs.InsertCssProductInputRequest.pb( css_product_inputs.InsertCssProductInputRequest() ) @@ -3170,6 +3224,7 @@ def test_insert_css_product_input_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = css_product_inputs.CssProductInput() + post_with_metadata.return_value = css_product_inputs.CssProductInput(), metadata client.insert_css_product_input( request, @@ -3181,6 +3236,7 @@ def test_insert_css_product_input_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_css_product_input_rest_bad_request( @@ -3445,11 +3501,15 @@ def test_update_css_product_input_rest_interceptors(null_interceptor): transports.CssProductInputsServiceRestInterceptor, "post_update_css_product_input", ) as post, mock.patch.object( + transports.CssProductInputsServiceRestInterceptor, + "post_update_css_product_input_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CssProductInputsServiceRestInterceptor, "pre_update_css_product_input", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = css_product_inputs.UpdateCssProductInputRequest.pb( css_product_inputs.UpdateCssProductInputRequest() ) @@ -3475,6 +3535,7 @@ def test_update_css_product_input_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = css_product_inputs.CssProductInput() + post_with_metadata.return_value = css_product_inputs.CssProductInput(), metadata client.update_css_product_input( request, @@ -3486,6 +3547,7 @@ def test_update_css_product_input_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_css_product_input_rest_bad_request( diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py index bbde0a0dd355..1ca65acd47ca 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py @@ -61,6 +61,13 @@ ) from google.shopping.css_v1.types import css_product_common, css_products +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -332,6 +339,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CssProductsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CssProductsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2731,10 +2781,14 @@ def test_get_css_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CssProductsServiceRestInterceptor, "post_get_css_product" ) as post, mock.patch.object( + transports.CssProductsServiceRestInterceptor, + "post_get_css_product_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CssProductsServiceRestInterceptor, "pre_get_css_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = css_products.GetCssProductRequest.pb( css_products.GetCssProductRequest() ) @@ -2758,6 +2812,7 @@ def test_get_css_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = css_products.CssProduct() + post_with_metadata.return_value = css_products.CssProduct(), metadata client.get_css_product( request, @@ -2769,6 +2824,7 @@ def test_get_css_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_css_products_rest_bad_request( @@ -2853,10 +2909,14 @@ def test_list_css_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CssProductsServiceRestInterceptor, "post_list_css_products" ) as post, mock.patch.object( + transports.CssProductsServiceRestInterceptor, + "post_list_css_products_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CssProductsServiceRestInterceptor, "pre_list_css_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = css_products.ListCssProductsRequest.pb( css_products.ListCssProductsRequest() ) @@ -2882,6 +2942,10 @@ def test_list_css_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = css_products.ListCssProductsResponse() + post_with_metadata.return_value = ( + css_products.ListCssProductsResponse(), + metadata, + ) client.list_css_products( request, @@ -2893,6 +2957,7 @@ def test_list_css_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/README.rst b/packages/google-shopping-merchant-accounts/README.rst index 0645f3a3b275..fcbb13bb21c1 100644 --- a/packages/google-shopping-merchant-accounts/README.rst +++ b/packages/google-shopping-merchant-accounts/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py index 355df6b536f8..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.3" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py index 355df6b536f8..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.3" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/client.py index 7b2617438d45..ff8fb6ef0000 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -496,6 +498,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/transports/rest.py index f50f616ca4c4..4174924f1f56 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_issue_service/transports/rest.py @@ -101,12 +101,37 @@ def post_list_account_issues( ) -> accountissue.ListAccountIssuesResponse: """Post-rpc interceptor for list_account_issues - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_account_issues_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountIssueService server but before - it is returned to user code. + it is returned to user code. This `post_list_account_issues` interceptor runs + before the `post_list_account_issues_with_metadata` interceptor. """ return response + def post_list_account_issues_with_metadata( + self, + response: accountissue.ListAccountIssuesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accountissue.ListAccountIssuesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_account_issues + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountIssueService server but before it is returned to user code. + + We recommend only using this `post_list_account_issues_with_metadata` + interceptor in new development instead of the `post_list_account_issues` interceptor. + When both interceptors are used, this `post_list_account_issues_with_metadata` interceptor runs after the + `post_list_account_issues` interceptor. The (possibly modified) response returned by + `post_list_account_issues` will be passed to + `post_list_account_issues_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AccountIssueServiceRestStub: @@ -316,6 +341,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_account_issues(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_account_issues_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/client.py index e861d5641259..37dffd5c87f4 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/transports/rest.py index 4c562090d9b4..c4736f56b65f 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/account_tax_service/transports/rest.py @@ -120,12 +120,35 @@ def post_get_account_tax( ) -> account_tax.AccountTax: """Post-rpc interceptor for get_account_tax - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_account_tax_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountTaxService server but before - it is returned to user code. + it is returned to user code. This `post_get_account_tax` interceptor runs + before the `post_get_account_tax_with_metadata` interceptor. """ return response + def post_get_account_tax_with_metadata( + self, + response: account_tax.AccountTax, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[account_tax.AccountTax, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_account_tax + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountTaxService server but before it is returned to user code. + + We recommend only using this `post_get_account_tax_with_metadata` + interceptor in new development instead of the `post_get_account_tax` interceptor. + When both interceptors are used, this `post_get_account_tax_with_metadata` interceptor runs after the + `post_get_account_tax` interceptor. The (possibly modified) response returned by + `post_get_account_tax` will be passed to + `post_get_account_tax_with_metadata`. + """ + return response, metadata + def pre_list_account_tax( self, request: account_tax.ListAccountTaxRequest, @@ -145,12 +168,37 @@ def post_list_account_tax( ) -> account_tax.ListAccountTaxResponse: """Post-rpc interceptor for list_account_tax - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_account_tax_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountTaxService server but before - it is returned to user code. + it is returned to user code. This `post_list_account_tax` interceptor runs + before the `post_list_account_tax_with_metadata` interceptor. """ return response + def post_list_account_tax_with_metadata( + self, + response: account_tax.ListAccountTaxResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + account_tax.ListAccountTaxResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_account_tax + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountTaxService server but before it is returned to user code. + + We recommend only using this `post_list_account_tax_with_metadata` + interceptor in new development instead of the `post_list_account_tax` interceptor. + When both interceptors are used, this `post_list_account_tax_with_metadata` interceptor runs after the + `post_list_account_tax` interceptor. The (possibly modified) response returned by + `post_list_account_tax` will be passed to + `post_list_account_tax_with_metadata`. + """ + return response, metadata + def pre_update_account_tax( self, request: gsma_account_tax.UpdateAccountTaxRequest, @@ -171,12 +219,35 @@ def post_update_account_tax( ) -> gsma_account_tax.AccountTax: """Post-rpc interceptor for update_account_tax - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_account_tax_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountTaxService server but before - it is returned to user code. + it is returned to user code. This `post_update_account_tax` interceptor runs + before the `post_update_account_tax_with_metadata` interceptor. """ return response + def post_update_account_tax_with_metadata( + self, + response: gsma_account_tax.AccountTax, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gsma_account_tax.AccountTax, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_account_tax + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountTaxService server but before it is returned to user code. + + We recommend only using this `post_update_account_tax_with_metadata` + interceptor in new development instead of the `post_update_account_tax` interceptor. + When both interceptors are used, this `post_update_account_tax_with_metadata` interceptor runs after the + `post_update_account_tax` interceptor. The (possibly modified) response returned by + `post_update_account_tax` will be passed to + `post_update_account_tax_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AccountTaxServiceRestStub: @@ -389,6 +460,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_account_tax(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_account_tax_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -540,6 +615,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_account_tax(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_account_tax_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -694,6 +773,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_account_tax(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_account_tax_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/client.py index b494944f8580..429dec6230c9 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -512,6 +514,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/transports/rest.py index ccc7fb9ca712..51c5fdd6a1b2 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/accounts_service/transports/rest.py @@ -139,12 +139,35 @@ def post_create_and_configure_account( ) -> accounts.Account: """Post-rpc interceptor for create_and_configure_account - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_and_configure_account_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_create_and_configure_account` interceptor runs + before the `post_create_and_configure_account_with_metadata` interceptor. """ return response + def post_create_and_configure_account_with_metadata( + self, + response: accounts.Account, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.Account, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_and_configure_account + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_create_and_configure_account_with_metadata` + interceptor in new development instead of the `post_create_and_configure_account` interceptor. + When both interceptors are used, this `post_create_and_configure_account_with_metadata` interceptor runs after the + `post_create_and_configure_account` interceptor. The (possibly modified) response returned by + `post_create_and_configure_account` will be passed to + `post_create_and_configure_account_with_metadata`. + """ + return response, metadata + def pre_delete_account( self, request: accounts.DeleteAccountRequest, @@ -172,12 +195,35 @@ def pre_get_account( def post_get_account(self, response: accounts.Account) -> accounts.Account: """Post-rpc interceptor for get_account - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_account_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_get_account` interceptor runs + before the `post_get_account_with_metadata` interceptor. """ return response + def post_get_account_with_metadata( + self, + response: accounts.Account, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.Account, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_account + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_get_account_with_metadata` + interceptor in new development instead of the `post_get_account` interceptor. + When both interceptors are used, this `post_get_account_with_metadata` interceptor runs after the + `post_get_account` interceptor. The (possibly modified) response returned by + `post_get_account` will be passed to + `post_get_account_with_metadata`. + """ + return response, metadata + def pre_list_accounts( self, request: accounts.ListAccountsRequest, @@ -195,12 +241,35 @@ def post_list_accounts( ) -> accounts.ListAccountsResponse: """Post-rpc interceptor for list_accounts - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_accounts_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_list_accounts` interceptor runs + before the `post_list_accounts_with_metadata` interceptor. """ return response + def post_list_accounts_with_metadata( + self, + response: accounts.ListAccountsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.ListAccountsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_accounts + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_list_accounts_with_metadata` + interceptor in new development instead of the `post_list_accounts` interceptor. + When both interceptors are used, this `post_list_accounts_with_metadata` interceptor runs after the + `post_list_accounts` interceptor. The (possibly modified) response returned by + `post_list_accounts` will be passed to + `post_list_accounts_with_metadata`. + """ + return response, metadata + def pre_list_sub_accounts( self, request: accounts.ListSubAccountsRequest, @@ -220,12 +289,37 @@ def post_list_sub_accounts( ) -> accounts.ListSubAccountsResponse: """Post-rpc interceptor for list_sub_accounts - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_sub_accounts_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_list_sub_accounts` interceptor runs + before the `post_list_sub_accounts_with_metadata` interceptor. """ return response + def post_list_sub_accounts_with_metadata( + self, + response: accounts.ListSubAccountsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts.ListSubAccountsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_sub_accounts + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_list_sub_accounts_with_metadata` + interceptor in new development instead of the `post_list_sub_accounts` interceptor. + When both interceptors are used, this `post_list_sub_accounts_with_metadata` interceptor runs after the + `post_list_sub_accounts` interceptor. The (possibly modified) response returned by + `post_list_sub_accounts` will be passed to + `post_list_sub_accounts_with_metadata`. + """ + return response, metadata + def pre_update_account( self, request: accounts.UpdateAccountRequest, @@ -241,12 +335,35 @@ def pre_update_account( def post_update_account(self, response: accounts.Account) -> accounts.Account: """Post-rpc interceptor for update_account - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_account_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AccountsService server but before - it is returned to user code. + it is returned to user code. This `post_update_account` interceptor runs + before the `post_update_account_with_metadata` interceptor. """ return response + def post_update_account_with_metadata( + self, + response: accounts.Account, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.Account, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_account + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AccountsService server but before it is returned to user code. + + We recommend only using this `post_update_account_with_metadata` + interceptor in new development instead of the `post_update_account` interceptor. + When both interceptors are used, this `post_update_account_with_metadata` interceptor runs after the + `post_update_account` interceptor. The (possibly modified) response returned by + `post_update_account` will be passed to + `post_update_account_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AccountsServiceRestStub: @@ -464,6 +581,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_and_configure_account(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_and_configure_account_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -710,6 +831,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_account(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_account_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -850,6 +975,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_accounts(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_accounts_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -992,6 +1121,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_sub_accounts(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_sub_accounts_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1140,6 +1273,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_account(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_account_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/client.py index 7e539b0f9167..237332995a03 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/transports/rest.py index c2b1813251d5..78e2b960cf0a 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/autofeed_settings_service/transports/rest.py @@ -110,12 +110,37 @@ def post_get_autofeed_settings( ) -> autofeedsettings.AutofeedSettings: """Post-rpc interceptor for get_autofeed_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_autofeed_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AutofeedSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_get_autofeed_settings` interceptor runs + before the `post_get_autofeed_settings_with_metadata` interceptor. """ return response + def post_get_autofeed_settings_with_metadata( + self, + response: autofeedsettings.AutofeedSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + autofeedsettings.AutofeedSettings, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_autofeed_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AutofeedSettingsService server but before it is returned to user code. + + We recommend only using this `post_get_autofeed_settings_with_metadata` + interceptor in new development instead of the `post_get_autofeed_settings` interceptor. + When both interceptors are used, this `post_get_autofeed_settings_with_metadata` interceptor runs after the + `post_get_autofeed_settings` interceptor. The (possibly modified) response returned by + `post_get_autofeed_settings` will be passed to + `post_get_autofeed_settings_with_metadata`. + """ + return response, metadata + def pre_update_autofeed_settings( self, request: autofeedsettings.UpdateAutofeedSettingsRequest, @@ -136,12 +161,37 @@ def post_update_autofeed_settings( ) -> autofeedsettings.AutofeedSettings: """Post-rpc interceptor for update_autofeed_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_autofeed_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AutofeedSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_update_autofeed_settings` interceptor runs + before the `post_update_autofeed_settings_with_metadata` interceptor. """ return response + def post_update_autofeed_settings_with_metadata( + self, + response: autofeedsettings.AutofeedSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + autofeedsettings.AutofeedSettings, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_autofeed_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AutofeedSettingsService server but before it is returned to user code. + + We recommend only using this `post_update_autofeed_settings_with_metadata` + interceptor in new development instead of the `post_update_autofeed_settings` interceptor. + When both interceptors are used, this `post_update_autofeed_settings_with_metadata` interceptor runs after the + `post_update_autofeed_settings` interceptor. The (possibly modified) response returned by + `post_update_autofeed_settings` will be passed to + `post_update_autofeed_settings_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class AutofeedSettingsServiceRestStub: @@ -356,6 +406,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_autofeed_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_autofeed_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -511,6 +565,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_autofeed_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_autofeed_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/client.py index 2dc21c12dd3d..9e3901aaca68 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/transports/rest.py index 56639f05a5cf..76649f10e510 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_identity_service/transports/rest.py @@ -110,12 +110,37 @@ def post_get_business_identity( ) -> businessidentity.BusinessIdentity: """Post-rpc interceptor for get_business_identity - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_business_identity_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BusinessIdentityService server but before - it is returned to user code. + it is returned to user code. This `post_get_business_identity` interceptor runs + before the `post_get_business_identity_with_metadata` interceptor. """ return response + def post_get_business_identity_with_metadata( + self, + response: businessidentity.BusinessIdentity, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + businessidentity.BusinessIdentity, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_business_identity + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BusinessIdentityService server but before it is returned to user code. + + We recommend only using this `post_get_business_identity_with_metadata` + interceptor in new development instead of the `post_get_business_identity` interceptor. + When both interceptors are used, this `post_get_business_identity_with_metadata` interceptor runs after the + `post_get_business_identity` interceptor. The (possibly modified) response returned by + `post_get_business_identity` will be passed to + `post_get_business_identity_with_metadata`. + """ + return response, metadata + def pre_update_business_identity( self, request: businessidentity.UpdateBusinessIdentityRequest, @@ -136,12 +161,37 @@ def post_update_business_identity( ) -> businessidentity.BusinessIdentity: """Post-rpc interceptor for update_business_identity - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_business_identity_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BusinessIdentityService server but before - it is returned to user code. + it is returned to user code. This `post_update_business_identity` interceptor runs + before the `post_update_business_identity_with_metadata` interceptor. """ return response + def post_update_business_identity_with_metadata( + self, + response: businessidentity.BusinessIdentity, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + businessidentity.BusinessIdentity, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_business_identity + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BusinessIdentityService server but before it is returned to user code. + + We recommend only using this `post_update_business_identity_with_metadata` + interceptor in new development instead of the `post_update_business_identity` interceptor. + When both interceptors are used, this `post_update_business_identity_with_metadata` interceptor runs after the + `post_update_business_identity` interceptor. The (possibly modified) response returned by + `post_update_business_identity` will be passed to + `post_update_business_identity_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class BusinessIdentityServiceRestStub: @@ -355,6 +405,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_business_identity(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_business_identity_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -509,6 +563,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_business_identity(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_business_identity_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/client.py index 78fc2fa851ff..20cf19bd4c9b 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -484,6 +486,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/transports/rest.py index 27e29fd0e255..cc7100b2fc35 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/business_info_service/transports/rest.py @@ -109,12 +109,35 @@ def post_get_business_info( ) -> businessinfo.BusinessInfo: """Post-rpc interceptor for get_business_info - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_business_info_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BusinessInfoService server but before - it is returned to user code. + it is returned to user code. This `post_get_business_info` interceptor runs + before the `post_get_business_info_with_metadata` interceptor. """ return response + def post_get_business_info_with_metadata( + self, + response: businessinfo.BusinessInfo, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[businessinfo.BusinessInfo, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_business_info + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BusinessInfoService server but before it is returned to user code. + + We recommend only using this `post_get_business_info_with_metadata` + interceptor in new development instead of the `post_get_business_info` interceptor. + When both interceptors are used, this `post_get_business_info_with_metadata` interceptor runs after the + `post_get_business_info` interceptor. The (possibly modified) response returned by + `post_get_business_info` will be passed to + `post_get_business_info_with_metadata`. + """ + return response, metadata + def pre_update_business_info( self, request: businessinfo.UpdateBusinessInfoRequest, @@ -134,12 +157,35 @@ def post_update_business_info( ) -> businessinfo.BusinessInfo: """Post-rpc interceptor for update_business_info - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_business_info_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BusinessInfoService server but before - it is returned to user code. + it is returned to user code. This `post_update_business_info` interceptor runs + before the `post_update_business_info_with_metadata` interceptor. """ return response + def post_update_business_info_with_metadata( + self, + response: businessinfo.BusinessInfo, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[businessinfo.BusinessInfo, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_business_info + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BusinessInfoService server but before it is returned to user code. + + We recommend only using this `post_update_business_info_with_metadata` + interceptor in new development instead of the `post_update_business_info` interceptor. + When both interceptors are used, this `post_update_business_info_with_metadata` interceptor runs after the + `post_update_business_info` interceptor. The (possibly modified) response returned by + `post_update_business_info` will be passed to + `post_update_business_info_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class BusinessInfoServiceRestStub: @@ -349,6 +395,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_business_info(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_business_info_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -502,6 +552,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_business_info(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_business_info_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/client.py index db65e710fa86..91f74406d12e 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -488,6 +490,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/transports/rest.py index 28c774418566..a14d8c45e24d 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/email_preferences_service/transports/rest.py @@ -110,12 +110,37 @@ def post_get_email_preferences( ) -> emailpreferences.EmailPreferences: """Post-rpc interceptor for get_email_preferences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_email_preferences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the EmailPreferencesService server but before - it is returned to user code. + it is returned to user code. This `post_get_email_preferences` interceptor runs + before the `post_get_email_preferences_with_metadata` interceptor. """ return response + def post_get_email_preferences_with_metadata( + self, + response: emailpreferences.EmailPreferences, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + emailpreferences.EmailPreferences, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_email_preferences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the EmailPreferencesService server but before it is returned to user code. + + We recommend only using this `post_get_email_preferences_with_metadata` + interceptor in new development instead of the `post_get_email_preferences` interceptor. + When both interceptors are used, this `post_get_email_preferences_with_metadata` interceptor runs after the + `post_get_email_preferences` interceptor. The (possibly modified) response returned by + `post_get_email_preferences` will be passed to + `post_get_email_preferences_with_metadata`. + """ + return response, metadata + def pre_update_email_preferences( self, request: emailpreferences.UpdateEmailPreferencesRequest, @@ -136,12 +161,37 @@ def post_update_email_preferences( ) -> emailpreferences.EmailPreferences: """Post-rpc interceptor for update_email_preferences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_email_preferences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the EmailPreferencesService server but before - it is returned to user code. + it is returned to user code. This `post_update_email_preferences` interceptor runs + before the `post_update_email_preferences_with_metadata` interceptor. """ return response + def post_update_email_preferences_with_metadata( + self, + response: emailpreferences.EmailPreferences, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + emailpreferences.EmailPreferences, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_email_preferences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the EmailPreferencesService server but before it is returned to user code. + + We recommend only using this `post_update_email_preferences_with_metadata` + interceptor in new development instead of the `post_update_email_preferences` interceptor. + When both interceptors are used, this `post_update_email_preferences_with_metadata` interceptor runs after the + `post_update_email_preferences` interceptor. The (possibly modified) response returned by + `post_update_email_preferences` will be passed to + `post_update_email_preferences_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class EmailPreferencesServiceRestStub: @@ -360,6 +410,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_email_preferences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_email_preferences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -517,6 +571,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_email_preferences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_email_preferences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/client.py index 358914a9dece..956ed7738251 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -479,6 +481,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/transports/rest.py index f39ea3706937..d070a8a82f12 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/homepage_service/transports/rest.py @@ -122,12 +122,35 @@ def pre_claim_homepage( def post_claim_homepage(self, response: homepage.Homepage) -> homepage.Homepage: """Post-rpc interceptor for claim_homepage - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_claim_homepage_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the HomepageService server but before - it is returned to user code. + it is returned to user code. This `post_claim_homepage` interceptor runs + before the `post_claim_homepage_with_metadata` interceptor. """ return response + def post_claim_homepage_with_metadata( + self, + response: homepage.Homepage, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[homepage.Homepage, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for claim_homepage + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the HomepageService server but before it is returned to user code. + + We recommend only using this `post_claim_homepage_with_metadata` + interceptor in new development instead of the `post_claim_homepage` interceptor. + When both interceptors are used, this `post_claim_homepage_with_metadata` interceptor runs after the + `post_claim_homepage` interceptor. The (possibly modified) response returned by + `post_claim_homepage` will be passed to + `post_claim_homepage_with_metadata`. + """ + return response, metadata + def pre_get_homepage( self, request: homepage.GetHomepageRequest, @@ -143,12 +166,35 @@ def pre_get_homepage( def post_get_homepage(self, response: homepage.Homepage) -> homepage.Homepage: """Post-rpc interceptor for get_homepage - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_homepage_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the HomepageService server but before - it is returned to user code. + it is returned to user code. This `post_get_homepage` interceptor runs + before the `post_get_homepage_with_metadata` interceptor. """ return response + def post_get_homepage_with_metadata( + self, + response: homepage.Homepage, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[homepage.Homepage, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_homepage + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the HomepageService server but before it is returned to user code. + + We recommend only using this `post_get_homepage_with_metadata` + interceptor in new development instead of the `post_get_homepage` interceptor. + When both interceptors are used, this `post_get_homepage_with_metadata` interceptor runs after the + `post_get_homepage` interceptor. The (possibly modified) response returned by + `post_get_homepage` will be passed to + `post_get_homepage_with_metadata`. + """ + return response, metadata + def pre_unclaim_homepage( self, request: homepage.UnclaimHomepageRequest, @@ -166,12 +212,35 @@ def pre_unclaim_homepage( def post_unclaim_homepage(self, response: homepage.Homepage) -> homepage.Homepage: """Post-rpc interceptor for unclaim_homepage - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_unclaim_homepage_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the HomepageService server but before - it is returned to user code. + it is returned to user code. This `post_unclaim_homepage` interceptor runs + before the `post_unclaim_homepage_with_metadata` interceptor. """ return response + def post_unclaim_homepage_with_metadata( + self, + response: homepage.Homepage, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[homepage.Homepage, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for unclaim_homepage + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the HomepageService server but before it is returned to user code. + + We recommend only using this `post_unclaim_homepage_with_metadata` + interceptor in new development instead of the `post_unclaim_homepage` interceptor. + When both interceptors are used, this `post_unclaim_homepage_with_metadata` interceptor runs after the + `post_unclaim_homepage` interceptor. The (possibly modified) response returned by + `post_unclaim_homepage` will be passed to + `post_unclaim_homepage_with_metadata`. + """ + return response, metadata + def pre_update_homepage( self, request: gsma_homepage.UpdateHomepageRequest, @@ -191,12 +260,35 @@ def post_update_homepage( ) -> gsma_homepage.Homepage: """Post-rpc interceptor for update_homepage - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_homepage_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the HomepageService server but before - it is returned to user code. + it is returned to user code. This `post_update_homepage` interceptor runs + before the `post_update_homepage_with_metadata` interceptor. """ return response + def post_update_homepage_with_metadata( + self, + response: gsma_homepage.Homepage, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gsma_homepage.Homepage, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_homepage + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the HomepageService server but before it is returned to user code. + + We recommend only using this `post_update_homepage_with_metadata` + interceptor in new development instead of the `post_update_homepage` interceptor. + When both interceptors are used, this `post_update_homepage_with_metadata` interceptor runs after the + `post_update_homepage` interceptor. The (possibly modified) response returned by + `post_update_homepage` will be passed to + `post_update_homepage_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class HomepageServiceRestStub: @@ -407,6 +499,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_claim_homepage(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_claim_homepage_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -547,6 +643,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_homepage(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_homepage_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -695,6 +795,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_unclaim_homepage(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_unclaim_homepage_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -841,6 +945,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_homepage(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_homepage_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/client.py index 893b5fcc9a31..5cd869bde717 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -492,6 +494,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/transports/rest.py index 4efb4dd8e9eb..15faed2cc30d 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/online_return_policy_service/transports/rest.py @@ -110,12 +110,37 @@ def post_get_online_return_policy( ) -> online_return_policy.OnlineReturnPolicy: """Post-rpc interceptor for get_online_return_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_online_return_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the OnlineReturnPolicyService server but before - it is returned to user code. + it is returned to user code. This `post_get_online_return_policy` interceptor runs + before the `post_get_online_return_policy_with_metadata` interceptor. """ return response + def post_get_online_return_policy_with_metadata( + self, + response: online_return_policy.OnlineReturnPolicy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + online_return_policy.OnlineReturnPolicy, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_online_return_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the OnlineReturnPolicyService server but before it is returned to user code. + + We recommend only using this `post_get_online_return_policy_with_metadata` + interceptor in new development instead of the `post_get_online_return_policy` interceptor. + When both interceptors are used, this `post_get_online_return_policy_with_metadata` interceptor runs after the + `post_get_online_return_policy` interceptor. The (possibly modified) response returned by + `post_get_online_return_policy` will be passed to + `post_get_online_return_policy_with_metadata`. + """ + return response, metadata + def pre_list_online_return_policies( self, request: online_return_policy.ListOnlineReturnPoliciesRequest, @@ -136,12 +161,38 @@ def post_list_online_return_policies( ) -> online_return_policy.ListOnlineReturnPoliciesResponse: """Post-rpc interceptor for list_online_return_policies - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_online_return_policies_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the OnlineReturnPolicyService server but before - it is returned to user code. + it is returned to user code. This `post_list_online_return_policies` interceptor runs + before the `post_list_online_return_policies_with_metadata` interceptor. """ return response + def post_list_online_return_policies_with_metadata( + self, + response: online_return_policy.ListOnlineReturnPoliciesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + online_return_policy.ListOnlineReturnPoliciesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_online_return_policies + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the OnlineReturnPolicyService server but before it is returned to user code. + + We recommend only using this `post_list_online_return_policies_with_metadata` + interceptor in new development instead of the `post_list_online_return_policies` interceptor. + When both interceptors are used, this `post_list_online_return_policies_with_metadata` interceptor runs after the + `post_list_online_return_policies` interceptor. The (possibly modified) response returned by + `post_list_online_return_policies` will be passed to + `post_list_online_return_policies_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class OnlineReturnPolicyServiceRestStub: @@ -363,6 +414,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_online_return_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_online_return_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -514,6 +569,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_online_return_policies(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_online_return_policies_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/client.py index d1c7f8a239c2..73c2f57e86df 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/transports/rest.py index 58a305791fd0..45c97f580664 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/programs_service/transports/rest.py @@ -121,12 +121,35 @@ def pre_disable_program( def post_disable_program(self, response: programs.Program) -> programs.Program: """Post-rpc interceptor for disable_program - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_disable_program_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProgramsService server but before - it is returned to user code. + it is returned to user code. This `post_disable_program` interceptor runs + before the `post_disable_program_with_metadata` interceptor. """ return response + def post_disable_program_with_metadata( + self, + response: programs.Program, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[programs.Program, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for disable_program + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProgramsService server but before it is returned to user code. + + We recommend only using this `post_disable_program_with_metadata` + interceptor in new development instead of the `post_disable_program` interceptor. + When both interceptors are used, this `post_disable_program_with_metadata` interceptor runs after the + `post_disable_program` interceptor. The (possibly modified) response returned by + `post_disable_program` will be passed to + `post_disable_program_with_metadata`. + """ + return response, metadata + def pre_enable_program( self, request: programs.EnableProgramRequest, @@ -142,12 +165,35 @@ def pre_enable_program( def post_enable_program(self, response: programs.Program) -> programs.Program: """Post-rpc interceptor for enable_program - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_enable_program_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProgramsService server but before - it is returned to user code. + it is returned to user code. This `post_enable_program` interceptor runs + before the `post_enable_program_with_metadata` interceptor. """ return response + def post_enable_program_with_metadata( + self, + response: programs.Program, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[programs.Program, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for enable_program + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProgramsService server but before it is returned to user code. + + We recommend only using this `post_enable_program_with_metadata` + interceptor in new development instead of the `post_enable_program` interceptor. + When both interceptors are used, this `post_enable_program_with_metadata` interceptor runs after the + `post_enable_program` interceptor. The (possibly modified) response returned by + `post_enable_program` will be passed to + `post_enable_program_with_metadata`. + """ + return response, metadata + def pre_get_program( self, request: programs.GetProgramRequest, @@ -163,12 +209,35 @@ def pre_get_program( def post_get_program(self, response: programs.Program) -> programs.Program: """Post-rpc interceptor for get_program - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_program_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProgramsService server but before - it is returned to user code. + it is returned to user code. This `post_get_program` interceptor runs + before the `post_get_program_with_metadata` interceptor. """ return response + def post_get_program_with_metadata( + self, + response: programs.Program, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[programs.Program, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_program + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProgramsService server but before it is returned to user code. + + We recommend only using this `post_get_program_with_metadata` + interceptor in new development instead of the `post_get_program` interceptor. + When both interceptors are used, this `post_get_program_with_metadata` interceptor runs after the + `post_get_program` interceptor. The (possibly modified) response returned by + `post_get_program` will be passed to + `post_get_program_with_metadata`. + """ + return response, metadata + def pre_list_programs( self, request: programs.ListProgramsRequest, @@ -186,12 +255,35 @@ def post_list_programs( ) -> programs.ListProgramsResponse: """Post-rpc interceptor for list_programs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_programs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProgramsService server but before - it is returned to user code. + it is returned to user code. This `post_list_programs` interceptor runs + before the `post_list_programs_with_metadata` interceptor. """ return response + def post_list_programs_with_metadata( + self, + response: programs.ListProgramsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[programs.ListProgramsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_programs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProgramsService server but before it is returned to user code. + + We recommend only using this `post_list_programs_with_metadata` + interceptor in new development instead of the `post_list_programs` interceptor. + When both interceptors are used, this `post_list_programs_with_metadata` interceptor runs after the + `post_list_programs` interceptor. The (possibly modified) response returned by + `post_list_programs` will be passed to + `post_list_programs_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ProgramsServiceRestStub: @@ -422,6 +514,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_disable_program(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_disable_program_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -578,6 +674,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_enable_program(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_enable_program_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -728,6 +828,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_program(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_program_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -871,6 +975,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_programs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_programs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/client.py index 95d239f36e75..a7d0887cd473 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -502,6 +504,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/transports/rest.py index c232076cad01..53d06e16ca50 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/regions_service/transports/rest.py @@ -126,12 +126,35 @@ def pre_create_region( def post_create_region(self, response: regions.Region) -> regions.Region: """Post-rpc interceptor for create_region - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_region_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionsService server but before - it is returned to user code. + it is returned to user code. This `post_create_region` interceptor runs + before the `post_create_region_with_metadata` interceptor. """ return response + def post_create_region_with_metadata( + self, + response: regions.Region, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[regions.Region, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_region + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionsService server but before it is returned to user code. + + We recommend only using this `post_create_region_with_metadata` + interceptor in new development instead of the `post_create_region` interceptor. + When both interceptors are used, this `post_create_region_with_metadata` interceptor runs after the + `post_create_region` interceptor. The (possibly modified) response returned by + `post_create_region` will be passed to + `post_create_region_with_metadata`. + """ + return response, metadata + def pre_delete_region( self, request: regions.DeleteRegionRequest, @@ -159,12 +182,35 @@ def pre_get_region( def post_get_region(self, response: regions.Region) -> regions.Region: """Post-rpc interceptor for get_region - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_region_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionsService server but before - it is returned to user code. + it is returned to user code. This `post_get_region` interceptor runs + before the `post_get_region_with_metadata` interceptor. """ return response + def post_get_region_with_metadata( + self, + response: regions.Region, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[regions.Region, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_region + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionsService server but before it is returned to user code. + + We recommend only using this `post_get_region_with_metadata` + interceptor in new development instead of the `post_get_region` interceptor. + When both interceptors are used, this `post_get_region_with_metadata` interceptor runs after the + `post_get_region` interceptor. The (possibly modified) response returned by + `post_get_region` will be passed to + `post_get_region_with_metadata`. + """ + return response, metadata + def pre_list_regions( self, request: regions.ListRegionsRequest, @@ -182,12 +228,35 @@ def post_list_regions( ) -> regions.ListRegionsResponse: """Post-rpc interceptor for list_regions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_regions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionsService server but before - it is returned to user code. + it is returned to user code. This `post_list_regions` interceptor runs + before the `post_list_regions_with_metadata` interceptor. """ return response + def post_list_regions_with_metadata( + self, + response: regions.ListRegionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[regions.ListRegionsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_regions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionsService server but before it is returned to user code. + + We recommend only using this `post_list_regions_with_metadata` + interceptor in new development instead of the `post_list_regions` interceptor. + When both interceptors are used, this `post_list_regions_with_metadata` interceptor runs after the + `post_list_regions` interceptor. The (possibly modified) response returned by + `post_list_regions` will be passed to + `post_list_regions_with_metadata`. + """ + return response, metadata + def pre_update_region( self, request: regions.UpdateRegionRequest, @@ -203,12 +272,35 @@ def pre_update_region( def post_update_region(self, response: regions.Region) -> regions.Region: """Post-rpc interceptor for update_region - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_region_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionsService server but before - it is returned to user code. + it is returned to user code. This `post_update_region` interceptor runs + before the `post_update_region_with_metadata` interceptor. """ return response + def post_update_region_with_metadata( + self, + response: regions.Region, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[regions.Region, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_region + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionsService server but before it is returned to user code. + + We recommend only using this `post_update_region_with_metadata` + interceptor in new development instead of the `post_update_region` interceptor. + When both interceptors are used, this `post_update_region_with_metadata` interceptor runs after the + `post_update_region` interceptor. The (possibly modified) response returned by + `post_update_region` will be passed to + `post_update_region_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class RegionsServiceRestStub: @@ -431,6 +523,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_region(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_region_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -689,6 +785,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_region(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_region_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -829,6 +929,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_regions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_regions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -983,6 +1087,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_region(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_region_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/client.py index cbb279ef081c..6ad4ddb39363 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -480,6 +482,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/transports/rest.py index da6b482e5420..e8ad3bb774ab 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/shipping_settings_service/transports/rest.py @@ -110,12 +110,37 @@ def post_get_shipping_settings( ) -> shippingsettings.ShippingSettings: """Post-rpc interceptor for get_shipping_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_shipping_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ShippingSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_get_shipping_settings` interceptor runs + before the `post_get_shipping_settings_with_metadata` interceptor. """ return response + def post_get_shipping_settings_with_metadata( + self, + response: shippingsettings.ShippingSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + shippingsettings.ShippingSettings, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_shipping_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ShippingSettingsService server but before it is returned to user code. + + We recommend only using this `post_get_shipping_settings_with_metadata` + interceptor in new development instead of the `post_get_shipping_settings` interceptor. + When both interceptors are used, this `post_get_shipping_settings_with_metadata` interceptor runs after the + `post_get_shipping_settings` interceptor. The (possibly modified) response returned by + `post_get_shipping_settings` will be passed to + `post_get_shipping_settings_with_metadata`. + """ + return response, metadata + def pre_insert_shipping_settings( self, request: shippingsettings.InsertShippingSettingsRequest, @@ -136,12 +161,37 @@ def post_insert_shipping_settings( ) -> shippingsettings.ShippingSettings: """Post-rpc interceptor for insert_shipping_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_shipping_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ShippingSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_shipping_settings` interceptor runs + before the `post_insert_shipping_settings_with_metadata` interceptor. """ return response + def post_insert_shipping_settings_with_metadata( + self, + response: shippingsettings.ShippingSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + shippingsettings.ShippingSettings, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for insert_shipping_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ShippingSettingsService server but before it is returned to user code. + + We recommend only using this `post_insert_shipping_settings_with_metadata` + interceptor in new development instead of the `post_insert_shipping_settings` interceptor. + When both interceptors are used, this `post_insert_shipping_settings_with_metadata` interceptor runs after the + `post_insert_shipping_settings` interceptor. The (possibly modified) response returned by + `post_insert_shipping_settings` will be passed to + `post_insert_shipping_settings_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ShippingSettingsServiceRestStub: @@ -354,6 +404,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_shipping_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_shipping_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -508,6 +562,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_shipping_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_shipping_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/client.py index 641416abee80..a9c471fabf29 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -527,6 +529,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/transports/rest.py index d5b957f37f2d..291e68a8eb3e 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_agreement_state_service/transports/rest.py @@ -110,12 +110,38 @@ def post_get_terms_of_service_agreement_state( ) -> termsofserviceagreementstate.TermsOfServiceAgreementState: """Post-rpc interceptor for get_terms_of_service_agreement_state - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_terms_of_service_agreement_state_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TermsOfServiceAgreementStateService server but before - it is returned to user code. + it is returned to user code. This `post_get_terms_of_service_agreement_state` interceptor runs + before the `post_get_terms_of_service_agreement_state_with_metadata` interceptor. """ return response + def post_get_terms_of_service_agreement_state_with_metadata( + self, + response: termsofserviceagreementstate.TermsOfServiceAgreementState, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + termsofserviceagreementstate.TermsOfServiceAgreementState, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_terms_of_service_agreement_state + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TermsOfServiceAgreementStateService server but before it is returned to user code. + + We recommend only using this `post_get_terms_of_service_agreement_state_with_metadata` + interceptor in new development instead of the `post_get_terms_of_service_agreement_state` interceptor. + When both interceptors are used, this `post_get_terms_of_service_agreement_state_with_metadata` interceptor runs after the + `post_get_terms_of_service_agreement_state` interceptor. The (possibly modified) response returned by + `post_get_terms_of_service_agreement_state` will be passed to + `post_get_terms_of_service_agreement_state_with_metadata`. + """ + return response, metadata + def pre_retrieve_for_application_terms_of_service_agreement_state( self, request: termsofserviceagreementstate.RetrieveForApplicationTermsOfServiceAgreementStateRequest, @@ -136,12 +162,38 @@ def post_retrieve_for_application_terms_of_service_agreement_state( ) -> termsofserviceagreementstate.TermsOfServiceAgreementState: """Post-rpc interceptor for retrieve_for_application_terms_of_service_agreement_state - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_retrieve_for_application_terms_of_service_agreement_state_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TermsOfServiceAgreementStateService server but before - it is returned to user code. + it is returned to user code. This `post_retrieve_for_application_terms_of_service_agreement_state` interceptor runs + before the `post_retrieve_for_application_terms_of_service_agreement_state_with_metadata` interceptor. """ return response + def post_retrieve_for_application_terms_of_service_agreement_state_with_metadata( + self, + response: termsofserviceagreementstate.TermsOfServiceAgreementState, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + termsofserviceagreementstate.TermsOfServiceAgreementState, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for retrieve_for_application_terms_of_service_agreement_state + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TermsOfServiceAgreementStateService server but before it is returned to user code. + + We recommend only using this `post_retrieve_for_application_terms_of_service_agreement_state_with_metadata` + interceptor in new development instead of the `post_retrieve_for_application_terms_of_service_agreement_state` interceptor. + When both interceptors are used, this `post_retrieve_for_application_terms_of_service_agreement_state_with_metadata` interceptor runs after the + `post_retrieve_for_application_terms_of_service_agreement_state` interceptor. The (possibly modified) response returned by + `post_retrieve_for_application_terms_of_service_agreement_state` will be passed to + `post_retrieve_for_application_terms_of_service_agreement_state_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class TermsOfServiceAgreementStateServiceRestStub: @@ -390,6 +442,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_terms_of_service_agreement_state(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_terms_of_service_agreement_state_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -573,6 +632,13 @@ def __call__( resp = self._interceptor.post_retrieve_for_application_terms_of_service_agreement_state( resp ) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_retrieve_for_application_terms_of_service_agreement_state_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/client.py index fb2a75c1f566..b96051f8f51c 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -496,6 +498,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/transports/rest.py index 152800891a4f..f67da3b0f9c7 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/terms_of_service_service/transports/rest.py @@ -129,12 +129,35 @@ def post_get_terms_of_service( ) -> termsofservice.TermsOfService: """Post-rpc interceptor for get_terms_of_service - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_terms_of_service_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TermsOfServiceService server but before - it is returned to user code. + it is returned to user code. This `post_get_terms_of_service` interceptor runs + before the `post_get_terms_of_service_with_metadata` interceptor. """ return response + def post_get_terms_of_service_with_metadata( + self, + response: termsofservice.TermsOfService, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[termsofservice.TermsOfService, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_terms_of_service + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TermsOfServiceService server but before it is returned to user code. + + We recommend only using this `post_get_terms_of_service_with_metadata` + interceptor in new development instead of the `post_get_terms_of_service` interceptor. + When both interceptors are used, this `post_get_terms_of_service_with_metadata` interceptor runs after the + `post_get_terms_of_service` interceptor. The (possibly modified) response returned by + `post_get_terms_of_service` will be passed to + `post_get_terms_of_service_with_metadata`. + """ + return response, metadata + def pre_retrieve_latest_terms_of_service( self, request: termsofservice.RetrieveLatestTermsOfServiceRequest, @@ -155,12 +178,35 @@ def post_retrieve_latest_terms_of_service( ) -> termsofservice.TermsOfService: """Post-rpc interceptor for retrieve_latest_terms_of_service - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_retrieve_latest_terms_of_service_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TermsOfServiceService server but before - it is returned to user code. + it is returned to user code. This `post_retrieve_latest_terms_of_service` interceptor runs + before the `post_retrieve_latest_terms_of_service_with_metadata` interceptor. """ return response + def post_retrieve_latest_terms_of_service_with_metadata( + self, + response: termsofservice.TermsOfService, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[termsofservice.TermsOfService, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for retrieve_latest_terms_of_service + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TermsOfServiceService server but before it is returned to user code. + + We recommend only using this `post_retrieve_latest_terms_of_service_with_metadata` + interceptor in new development instead of the `post_retrieve_latest_terms_of_service` interceptor. + When both interceptors are used, this `post_retrieve_latest_terms_of_service_with_metadata` interceptor runs after the + `post_retrieve_latest_terms_of_service` interceptor. The (possibly modified) response returned by + `post_retrieve_latest_terms_of_service` will be passed to + `post_retrieve_latest_terms_of_service_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class TermsOfServiceServiceRestStub: @@ -481,6 +527,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_terms_of_service(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_terms_of_service_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -628,6 +678,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_retrieve_latest_terms_of_service(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_retrieve_latest_terms_of_service_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/client.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/client.py index 2a5d86474254..2aa2c603e789 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/client.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -496,6 +498,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/transports/rest.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/transports/rest.py index 4421b4cf14d2..29d5d54d9aee 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/transports/rest.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/services/user_service/transports/rest.py @@ -127,12 +127,35 @@ def pre_create_user( def post_create_user(self, response: gsma_user.User) -> gsma_user.User: """Post-rpc interceptor for create_user - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_user_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserService server but before - it is returned to user code. + it is returned to user code. This `post_create_user` interceptor runs + before the `post_create_user_with_metadata` interceptor. """ return response + def post_create_user_with_metadata( + self, + response: gsma_user.User, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gsma_user.User, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_user + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserService server but before it is returned to user code. + + We recommend only using this `post_create_user_with_metadata` + interceptor in new development instead of the `post_create_user` interceptor. + When both interceptors are used, this `post_create_user_with_metadata` interceptor runs after the + `post_create_user` interceptor. The (possibly modified) response returned by + `post_create_user` will be passed to + `post_create_user_with_metadata`. + """ + return response, metadata + def pre_delete_user( self, request: user.DeleteUserRequest, @@ -160,12 +183,33 @@ def pre_get_user( def post_get_user(self, response: user.User) -> user.User: """Post-rpc interceptor for get_user - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_user_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserService server but before - it is returned to user code. + it is returned to user code. This `post_get_user` interceptor runs + before the `post_get_user_with_metadata` interceptor. """ return response + def post_get_user_with_metadata( + self, response: user.User, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[user.User, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_user + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserService server but before it is returned to user code. + + We recommend only using this `post_get_user_with_metadata` + interceptor in new development instead of the `post_get_user` interceptor. + When both interceptors are used, this `post_get_user_with_metadata` interceptor runs after the + `post_get_user` interceptor. The (possibly modified) response returned by + `post_get_user` will be passed to + `post_get_user_with_metadata`. + """ + return response, metadata + def pre_list_users( self, request: user.ListUsersRequest, @@ -183,12 +227,35 @@ def post_list_users( ) -> user.ListUsersResponse: """Post-rpc interceptor for list_users - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_users_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserService server but before - it is returned to user code. + it is returned to user code. This `post_list_users` interceptor runs + before the `post_list_users_with_metadata` interceptor. """ return response + def post_list_users_with_metadata( + self, + response: user.ListUsersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[user.ListUsersResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_users + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserService server but before it is returned to user code. + + We recommend only using this `post_list_users_with_metadata` + interceptor in new development instead of the `post_list_users` interceptor. + When both interceptors are used, this `post_list_users_with_metadata` interceptor runs after the + `post_list_users` interceptor. The (possibly modified) response returned by + `post_list_users` will be passed to + `post_list_users_with_metadata`. + """ + return response, metadata + def pre_update_user( self, request: gsma_user.UpdateUserRequest, @@ -204,12 +271,35 @@ def pre_update_user( def post_update_user(self, response: gsma_user.User) -> gsma_user.User: """Post-rpc interceptor for update_user - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_user_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserService server but before - it is returned to user code. + it is returned to user code. This `post_update_user` interceptor runs + before the `post_update_user_with_metadata` interceptor. """ return response + def post_update_user_with_metadata( + self, + response: gsma_user.User, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gsma_user.User, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_user + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserService server but before it is returned to user code. + + We recommend only using this `post_update_user_with_metadata` + interceptor in new development instead of the `post_update_user` interceptor. + When both interceptors are used, this `post_update_user_with_metadata` interceptor runs after the + `post_update_user` interceptor. The (possibly modified) response returned by + `post_update_user` will be passed to + `post_update_user_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class UserServiceRestStub: @@ -426,6 +516,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_user(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_user_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -680,6 +774,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_user(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_user_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -822,6 +920,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_users(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_users_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -974,6 +1076,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_user(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_user_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-accounts/noxfile.py b/packages/google-shopping-merchant-accounts/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-accounts/noxfile.py +++ b/packages/google-shopping-merchant-accounts/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json b/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json index 892048ad1ce6..c736f9d3c831 100644 --- a/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json +++ b/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-accounts", - "version": "0.2.3" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_issue_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_issue_service.py index f55fae63fdf7..731e9e1538a6 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_issue_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_issue_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import accountissue +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -333,6 +340,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AccountIssueServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AccountIssueServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2193,10 +2243,14 @@ def test_list_account_issues_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountIssueServiceRestInterceptor, "post_list_account_issues" ) as post, mock.patch.object( + transports.AccountIssueServiceRestInterceptor, + "post_list_account_issues_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountIssueServiceRestInterceptor, "pre_list_account_issues" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accountissue.ListAccountIssuesRequest.pb( accountissue.ListAccountIssuesRequest() ) @@ -2222,6 +2276,10 @@ def test_list_account_issues_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accountissue.ListAccountIssuesResponse() + post_with_metadata.return_value = ( + accountissue.ListAccountIssuesResponse(), + metadata, + ) client.list_account_issues( request, @@ -2233,6 +2291,7 @@ def test_list_account_issues_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_tax_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_tax_service.py index e219d7f3360f..daeaeb8eb05c 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_tax_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_account_tax_service.py @@ -67,6 +67,13 @@ from google.shopping.merchant_accounts_v1beta.types import account_tax from google.shopping.merchant_accounts_v1beta.types import tax_rule +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -334,6 +341,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AccountTaxServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AccountTaxServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3286,10 +3336,14 @@ def test_get_account_tax_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "post_get_account_tax" ) as post, mock.patch.object( + transports.AccountTaxServiceRestInterceptor, + "post_get_account_tax_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "pre_get_account_tax" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = account_tax.GetAccountTaxRequest.pb( account_tax.GetAccountTaxRequest() ) @@ -3313,6 +3367,7 @@ def test_get_account_tax_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = account_tax.AccountTax() + post_with_metadata.return_value = account_tax.AccountTax(), metadata client.get_account_tax( request, @@ -3324,6 +3379,7 @@ def test_get_account_tax_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_account_tax_rest_bad_request( @@ -3408,10 +3464,14 @@ def test_list_account_tax_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "post_list_account_tax" ) as post, mock.patch.object( + transports.AccountTaxServiceRestInterceptor, + "post_list_account_tax_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "pre_list_account_tax" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = account_tax.ListAccountTaxRequest.pb( account_tax.ListAccountTaxRequest() ) @@ -3437,6 +3497,7 @@ def test_list_account_tax_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = account_tax.ListAccountTaxResponse() + post_with_metadata.return_value = account_tax.ListAccountTaxResponse(), metadata client.list_account_tax( request, @@ -3448,6 +3509,7 @@ def test_list_account_tax_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_account_tax_rest_bad_request( @@ -3619,10 +3681,14 @@ def test_update_account_tax_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "post_update_account_tax" ) as post, mock.patch.object( + transports.AccountTaxServiceRestInterceptor, + "post_update_account_tax_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountTaxServiceRestInterceptor, "pre_update_account_tax" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = gsma_account_tax.UpdateAccountTaxRequest.pb( gsma_account_tax.UpdateAccountTaxRequest() ) @@ -3648,6 +3714,7 @@ def test_update_account_tax_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gsma_account_tax.AccountTax() + post_with_metadata.return_value = gsma_account_tax.AccountTax(), metadata client.update_account_tax( request, @@ -3659,6 +3726,7 @@ def test_update_account_tax_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_accounts_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_accounts_service.py index 672309d4d693..a44c792fce7c 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_accounts_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_accounts_service.py @@ -67,6 +67,13 @@ user, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AccountsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AccountsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4748,10 +4798,13 @@ def test_get_account_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_get_account" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, "post_get_account_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_get_account" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.GetAccountRequest.pb(accounts.GetAccountRequest()) transcode.return_value = { "method": "post", @@ -4773,6 +4826,7 @@ def test_get_account_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.Account() + post_with_metadata.return_value = accounts.Account(), metadata client.get_account( request, @@ -4784,6 +4838,7 @@ def test_get_account_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_and_configure_account_rest_bad_request( @@ -4878,10 +4933,14 @@ def test_create_and_configure_account_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_create_and_configure_account" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, + "post_create_and_configure_account_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_create_and_configure_account" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.CreateAndConfigureAccountRequest.pb( accounts.CreateAndConfigureAccountRequest() ) @@ -4905,6 +4964,7 @@ def test_create_and_configure_account_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.Account() + post_with_metadata.return_value = accounts.Account(), metadata client.create_and_configure_account( request, @@ -4916,6 +4976,7 @@ def test_create_and_configure_account_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_account_rest_bad_request(request_type=accounts.DeleteAccountRequest): @@ -5189,10 +5250,13 @@ def test_update_account_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_update_account" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, "post_update_account_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_update_account" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.UpdateAccountRequest.pb(accounts.UpdateAccountRequest()) transcode.return_value = { "method": "post", @@ -5214,6 +5278,7 @@ def test_update_account_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.Account() + post_with_metadata.return_value = accounts.Account(), metadata client.update_account( request, @@ -5225,6 +5290,7 @@ def test_update_account_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_accounts_rest_bad_request(request_type=accounts.ListAccountsRequest): @@ -5307,10 +5373,13 @@ def test_list_accounts_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_list_accounts" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, "post_list_accounts_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_list_accounts" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.ListAccountsRequest.pb(accounts.ListAccountsRequest()) transcode.return_value = { "method": "post", @@ -5334,6 +5403,7 @@ def test_list_accounts_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.ListAccountsResponse() + post_with_metadata.return_value = accounts.ListAccountsResponse(), metadata client.list_accounts( request, @@ -5345,6 +5415,7 @@ def test_list_accounts_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_sub_accounts_rest_bad_request( @@ -5429,10 +5500,14 @@ def test_list_sub_accounts_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AccountsServiceRestInterceptor, "post_list_sub_accounts" ) as post, mock.patch.object( + transports.AccountsServiceRestInterceptor, + "post_list_sub_accounts_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AccountsServiceRestInterceptor, "pre_list_sub_accounts" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = accounts.ListSubAccountsRequest.pb( accounts.ListSubAccountsRequest() ) @@ -5458,6 +5533,7 @@ def test_list_sub_accounts_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = accounts.ListSubAccountsResponse() + post_with_metadata.return_value = accounts.ListSubAccountsResponse(), metadata client.list_sub_accounts( request, @@ -5469,6 +5545,7 @@ def test_list_sub_accounts_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_autofeed_settings_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_autofeed_settings_service.py index 27f14e47def8..c2337594cfe9 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_autofeed_settings_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_autofeed_settings_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import autofeedsettings +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AutofeedSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AutofeedSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2529,10 +2579,14 @@ def test_get_autofeed_settings_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.AutofeedSettingsServiceRestInterceptor, "post_get_autofeed_settings" ) as post, mock.patch.object( + transports.AutofeedSettingsServiceRestInterceptor, + "post_get_autofeed_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AutofeedSettingsServiceRestInterceptor, "pre_get_autofeed_settings" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = autofeedsettings.GetAutofeedSettingsRequest.pb( autofeedsettings.GetAutofeedSettingsRequest() ) @@ -2558,6 +2612,7 @@ def test_get_autofeed_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = autofeedsettings.AutofeedSettings() + post_with_metadata.return_value = autofeedsettings.AutofeedSettings(), metadata client.get_autofeed_settings( request, @@ -2569,6 +2624,7 @@ def test_get_autofeed_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_autofeed_settings_rest_bad_request( @@ -2732,11 +2788,15 @@ def test_update_autofeed_settings_rest_interceptors(null_interceptor): transports.AutofeedSettingsServiceRestInterceptor, "post_update_autofeed_settings", ) as post, mock.patch.object( + transports.AutofeedSettingsServiceRestInterceptor, + "post_update_autofeed_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AutofeedSettingsServiceRestInterceptor, "pre_update_autofeed_settings", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = autofeedsettings.UpdateAutofeedSettingsRequest.pb( autofeedsettings.UpdateAutofeedSettingsRequest() ) @@ -2762,6 +2822,7 @@ def test_update_autofeed_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = autofeedsettings.AutofeedSettings() + post_with_metadata.return_value = autofeedsettings.AutofeedSettings(), metadata client.update_autofeed_settings( request, @@ -2773,6 +2834,7 @@ def test_update_autofeed_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_identity_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_identity_service.py index fda9d2bbbf68..8ed1dea84fa7 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_identity_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_identity_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import businessidentity +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = BusinessIdentityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = BusinessIdentityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2532,10 +2582,14 @@ def test_get_business_identity_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.BusinessIdentityServiceRestInterceptor, "post_get_business_identity" ) as post, mock.patch.object( + transports.BusinessIdentityServiceRestInterceptor, + "post_get_business_identity_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.BusinessIdentityServiceRestInterceptor, "pre_get_business_identity" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = businessidentity.GetBusinessIdentityRequest.pb( businessidentity.GetBusinessIdentityRequest() ) @@ -2561,6 +2615,7 @@ def test_get_business_identity_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = businessidentity.BusinessIdentity() + post_with_metadata.return_value = businessidentity.BusinessIdentity(), metadata client.get_business_identity( request, @@ -2572,6 +2627,7 @@ def test_get_business_identity_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_business_identity_rest_bad_request( @@ -2740,11 +2796,15 @@ def test_update_business_identity_rest_interceptors(null_interceptor): transports.BusinessIdentityServiceRestInterceptor, "post_update_business_identity", ) as post, mock.patch.object( + transports.BusinessIdentityServiceRestInterceptor, + "post_update_business_identity_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.BusinessIdentityServiceRestInterceptor, "pre_update_business_identity", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = businessidentity.UpdateBusinessIdentityRequest.pb( businessidentity.UpdateBusinessIdentityRequest() ) @@ -2770,6 +2830,7 @@ def test_update_business_identity_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = businessidentity.BusinessIdentity() + post_with_metadata.return_value = businessidentity.BusinessIdentity(), metadata client.update_business_identity( request, @@ -2781,6 +2842,7 @@ def test_update_business_identity_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_info_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_info_service.py index 55f233b43794..a044c11b0962 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_info_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_business_info_service.py @@ -66,6 +66,13 @@ phoneverificationstate, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = BusinessInfoServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = BusinessInfoServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2549,10 +2599,14 @@ def test_get_business_info_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.BusinessInfoServiceRestInterceptor, "post_get_business_info" ) as post, mock.patch.object( + transports.BusinessInfoServiceRestInterceptor, + "post_get_business_info_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.BusinessInfoServiceRestInterceptor, "pre_get_business_info" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = businessinfo.GetBusinessInfoRequest.pb( businessinfo.GetBusinessInfoRequest() ) @@ -2576,6 +2630,7 @@ def test_get_business_info_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = businessinfo.BusinessInfo() + post_with_metadata.return_value = businessinfo.BusinessInfo(), metadata client.get_business_info( request, @@ -2587,6 +2642,7 @@ def test_get_business_info_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_business_info_rest_bad_request( @@ -2775,10 +2831,14 @@ def test_update_business_info_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.BusinessInfoServiceRestInterceptor, "post_update_business_info" ) as post, mock.patch.object( + transports.BusinessInfoServiceRestInterceptor, + "post_update_business_info_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.BusinessInfoServiceRestInterceptor, "pre_update_business_info" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = businessinfo.UpdateBusinessInfoRequest.pb( businessinfo.UpdateBusinessInfoRequest() ) @@ -2802,6 +2862,7 @@ def test_update_business_info_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = businessinfo.BusinessInfo() + post_with_metadata.return_value = businessinfo.BusinessInfo(), metadata client.update_business_info( request, @@ -2813,6 +2874,7 @@ def test_update_business_info_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_email_preferences_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_email_preferences_service.py index aa20e576c90a..1a3c5ac9a228 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_email_preferences_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_email_preferences_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import emailpreferences +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = EmailPreferencesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = EmailPreferencesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2529,10 +2579,14 @@ def test_get_email_preferences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.EmailPreferencesServiceRestInterceptor, "post_get_email_preferences" ) as post, mock.patch.object( + transports.EmailPreferencesServiceRestInterceptor, + "post_get_email_preferences_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.EmailPreferencesServiceRestInterceptor, "pre_get_email_preferences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = emailpreferences.GetEmailPreferencesRequest.pb( emailpreferences.GetEmailPreferencesRequest() ) @@ -2558,6 +2612,7 @@ def test_get_email_preferences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = emailpreferences.EmailPreferences() + post_with_metadata.return_value = emailpreferences.EmailPreferences(), metadata client.get_email_preferences( request, @@ -2569,6 +2624,7 @@ def test_get_email_preferences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_email_preferences_rest_bad_request( @@ -2735,11 +2791,15 @@ def test_update_email_preferences_rest_interceptors(null_interceptor): transports.EmailPreferencesServiceRestInterceptor, "post_update_email_preferences", ) as post, mock.patch.object( + transports.EmailPreferencesServiceRestInterceptor, + "post_update_email_preferences_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.EmailPreferencesServiceRestInterceptor, "pre_update_email_preferences", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = emailpreferences.UpdateEmailPreferencesRequest.pb( emailpreferences.UpdateEmailPreferencesRequest() ) @@ -2765,6 +2825,7 @@ def test_update_email_preferences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = emailpreferences.EmailPreferences() + post_with_metadata.return_value = emailpreferences.EmailPreferences(), metadata client.update_email_preferences( request, @@ -2776,6 +2837,7 @@ def test_update_email_preferences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_homepage_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_homepage_service.py index 3c1c890a3c77..a254c4b4fa1d 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_homepage_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_homepage_service.py @@ -61,6 +61,13 @@ from google.shopping.merchant_accounts_v1beta.types import homepage as gsma_homepage from google.shopping.merchant_accounts_v1beta.types import homepage +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = HomepageServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = HomepageServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3261,10 +3311,13 @@ def test_get_homepage_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.HomepageServiceRestInterceptor, "post_get_homepage" ) as post, mock.patch.object( + transports.HomepageServiceRestInterceptor, "post_get_homepage_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.HomepageServiceRestInterceptor, "pre_get_homepage" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = homepage.GetHomepageRequest.pb(homepage.GetHomepageRequest()) transcode.return_value = { "method": "post", @@ -3286,6 +3339,7 @@ def test_get_homepage_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = homepage.Homepage() + post_with_metadata.return_value = homepage.Homepage(), metadata client.get_homepage( request, @@ -3297,6 +3351,7 @@ def test_get_homepage_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_homepage_rest_bad_request( @@ -3457,10 +3512,13 @@ def test_update_homepage_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.HomepageServiceRestInterceptor, "post_update_homepage" ) as post, mock.patch.object( + transports.HomepageServiceRestInterceptor, "post_update_homepage_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.HomepageServiceRestInterceptor, "pre_update_homepage" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = gsma_homepage.UpdateHomepageRequest.pb( gsma_homepage.UpdateHomepageRequest() ) @@ -3484,6 +3542,7 @@ def test_update_homepage_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gsma_homepage.Homepage() + post_with_metadata.return_value = gsma_homepage.Homepage(), metadata client.update_homepage( request, @@ -3495,6 +3554,7 @@ def test_update_homepage_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_claim_homepage_rest_bad_request(request_type=homepage.ClaimHomepageRequest): @@ -3581,10 +3641,13 @@ def test_claim_homepage_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.HomepageServiceRestInterceptor, "post_claim_homepage" ) as post, mock.patch.object( + transports.HomepageServiceRestInterceptor, "post_claim_homepage_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.HomepageServiceRestInterceptor, "pre_claim_homepage" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = homepage.ClaimHomepageRequest.pb(homepage.ClaimHomepageRequest()) transcode.return_value = { "method": "post", @@ -3606,6 +3669,7 @@ def test_claim_homepage_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = homepage.Homepage() + post_with_metadata.return_value = homepage.Homepage(), metadata client.claim_homepage( request, @@ -3617,6 +3681,7 @@ def test_claim_homepage_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_unclaim_homepage_rest_bad_request( @@ -3705,10 +3770,13 @@ def test_unclaim_homepage_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.HomepageServiceRestInterceptor, "post_unclaim_homepage" ) as post, mock.patch.object( + transports.HomepageServiceRestInterceptor, "post_unclaim_homepage_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.HomepageServiceRestInterceptor, "pre_unclaim_homepage" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = homepage.UnclaimHomepageRequest.pb( homepage.UnclaimHomepageRequest() ) @@ -3732,6 +3800,7 @@ def test_unclaim_homepage_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = homepage.Homepage() + post_with_metadata.return_value = homepage.Homepage(), metadata client.unclaim_homepage( request, @@ -3743,6 +3812,7 @@ def test_unclaim_homepage_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_online_return_policy_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_online_return_policy_service.py index 2f65f8b7cb60..063b6412bde7 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_online_return_policy_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_online_return_policy_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import online_return_policy +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = OnlineReturnPolicyServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = OnlineReturnPolicyServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2884,11 +2934,15 @@ def test_get_online_return_policy_rest_interceptors(null_interceptor): transports.OnlineReturnPolicyServiceRestInterceptor, "post_get_online_return_policy", ) as post, mock.patch.object( + transports.OnlineReturnPolicyServiceRestInterceptor, + "post_get_online_return_policy_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.OnlineReturnPolicyServiceRestInterceptor, "pre_get_online_return_policy", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = online_return_policy.GetOnlineReturnPolicyRequest.pb( online_return_policy.GetOnlineReturnPolicyRequest() ) @@ -2914,6 +2968,10 @@ def test_get_online_return_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = online_return_policy.OnlineReturnPolicy() + post_with_metadata.return_value = ( + online_return_policy.OnlineReturnPolicy(), + metadata, + ) client.get_online_return_policy( request, @@ -2925,6 +2983,7 @@ def test_get_online_return_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_online_return_policies_rest_bad_request( @@ -3012,11 +3071,15 @@ def test_list_online_return_policies_rest_interceptors(null_interceptor): transports.OnlineReturnPolicyServiceRestInterceptor, "post_list_online_return_policies", ) as post, mock.patch.object( + transports.OnlineReturnPolicyServiceRestInterceptor, + "post_list_online_return_policies_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.OnlineReturnPolicyServiceRestInterceptor, "pre_list_online_return_policies", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = online_return_policy.ListOnlineReturnPoliciesRequest.pb( online_return_policy.ListOnlineReturnPoliciesRequest() ) @@ -3042,6 +3105,10 @@ def test_list_online_return_policies_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = online_return_policy.ListOnlineReturnPoliciesResponse() + post_with_metadata.return_value = ( + online_return_policy.ListOnlineReturnPoliciesResponse(), + metadata, + ) client.list_online_return_policies( request, @@ -3053,6 +3120,7 @@ def test_list_online_return_policies_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_programs_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_programs_service.py index efa73d73a38f..8bf9fd2e4987 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_programs_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_programs_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import programs +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -318,6 +325,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProgramsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProgramsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3794,10 +3844,13 @@ def test_get_program_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProgramsServiceRestInterceptor, "post_get_program" ) as post, mock.patch.object( + transports.ProgramsServiceRestInterceptor, "post_get_program_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProgramsServiceRestInterceptor, "pre_get_program" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = programs.GetProgramRequest.pb(programs.GetProgramRequest()) transcode.return_value = { "method": "post", @@ -3819,6 +3872,7 @@ def test_get_program_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = programs.Program() + post_with_metadata.return_value = programs.Program(), metadata client.get_program( request, @@ -3830,6 +3884,7 @@ def test_get_program_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_programs_rest_bad_request(request_type=programs.ListProgramsRequest): @@ -3912,10 +3967,13 @@ def test_list_programs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProgramsServiceRestInterceptor, "post_list_programs" ) as post, mock.patch.object( + transports.ProgramsServiceRestInterceptor, "post_list_programs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProgramsServiceRestInterceptor, "pre_list_programs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = programs.ListProgramsRequest.pb(programs.ListProgramsRequest()) transcode.return_value = { "method": "post", @@ -3939,6 +3997,7 @@ def test_list_programs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = programs.ListProgramsResponse() + post_with_metadata.return_value = programs.ListProgramsResponse(), metadata client.list_programs( request, @@ -3950,6 +4009,7 @@ def test_list_programs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_enable_program_rest_bad_request(request_type=programs.EnableProgramRequest): @@ -4038,10 +4098,13 @@ def test_enable_program_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProgramsServiceRestInterceptor, "post_enable_program" ) as post, mock.patch.object( + transports.ProgramsServiceRestInterceptor, "post_enable_program_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProgramsServiceRestInterceptor, "pre_enable_program" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = programs.EnableProgramRequest.pb(programs.EnableProgramRequest()) transcode.return_value = { "method": "post", @@ -4063,6 +4126,7 @@ def test_enable_program_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = programs.Program() + post_with_metadata.return_value = programs.Program(), metadata client.enable_program( request, @@ -4074,6 +4138,7 @@ def test_enable_program_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_disable_program_rest_bad_request(request_type=programs.DisableProgramRequest): @@ -4162,10 +4227,13 @@ def test_disable_program_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProgramsServiceRestInterceptor, "post_disable_program" ) as post, mock.patch.object( + transports.ProgramsServiceRestInterceptor, "post_disable_program_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProgramsServiceRestInterceptor, "pre_disable_program" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = programs.DisableProgramRequest.pb(programs.DisableProgramRequest()) transcode.return_value = { "method": "post", @@ -4187,6 +4255,7 @@ def test_disable_program_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = programs.Program() + post_with_metadata.return_value = programs.Program(), metadata client.disable_program( request, @@ -4198,6 +4267,7 @@ def test_disable_program_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_regions_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_regions_service.py index 9a2f58394544..723f77bdcd95 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_regions_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_regions_service.py @@ -62,6 +62,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import regions +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -320,6 +327,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RegionsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RegionsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4311,10 +4361,13 @@ def test_get_region_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RegionsServiceRestInterceptor, "post_get_region" ) as post, mock.patch.object( + transports.RegionsServiceRestInterceptor, "post_get_region_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RegionsServiceRestInterceptor, "pre_get_region" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regions.GetRegionRequest.pb(regions.GetRegionRequest()) transcode.return_value = { "method": "post", @@ -4336,6 +4389,7 @@ def test_get_region_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regions.Region() + post_with_metadata.return_value = regions.Region(), metadata client.get_region( request, @@ -4347,6 +4401,7 @@ def test_get_region_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_region_rest_bad_request(request_type=regions.CreateRegionRequest): @@ -4509,10 +4564,13 @@ def test_create_region_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RegionsServiceRestInterceptor, "post_create_region" ) as post, mock.patch.object( + transports.RegionsServiceRestInterceptor, "post_create_region_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RegionsServiceRestInterceptor, "pre_create_region" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regions.CreateRegionRequest.pb(regions.CreateRegionRequest()) transcode.return_value = { "method": "post", @@ -4534,6 +4592,7 @@ def test_create_region_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regions.Region() + post_with_metadata.return_value = regions.Region(), metadata client.create_region( request, @@ -4545,6 +4604,7 @@ def test_create_region_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_region_rest_bad_request(request_type=regions.UpdateRegionRequest): @@ -4707,10 +4767,13 @@ def test_update_region_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RegionsServiceRestInterceptor, "post_update_region" ) as post, mock.patch.object( + transports.RegionsServiceRestInterceptor, "post_update_region_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RegionsServiceRestInterceptor, "pre_update_region" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regions.UpdateRegionRequest.pb(regions.UpdateRegionRequest()) transcode.return_value = { "method": "post", @@ -4732,6 +4795,7 @@ def test_update_region_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regions.Region() + post_with_metadata.return_value = regions.Region(), metadata client.update_region( request, @@ -4743,6 +4807,7 @@ def test_update_region_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_region_rest_bad_request(request_type=regions.DeleteRegionRequest): @@ -4930,10 +4995,13 @@ def test_list_regions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RegionsServiceRestInterceptor, "post_list_regions" ) as post, mock.patch.object( + transports.RegionsServiceRestInterceptor, "post_list_regions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RegionsServiceRestInterceptor, "pre_list_regions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regions.ListRegionsRequest.pb(regions.ListRegionsRequest()) transcode.return_value = { "method": "post", @@ -4957,6 +5025,7 @@ def test_list_regions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regions.ListRegionsResponse() + post_with_metadata.return_value = regions.ListRegionsResponse(), metadata client.list_regions( request, @@ -4968,6 +5037,7 @@ def test_list_regions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_shipping_settings_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_shipping_settings_service.py index c1e7127471a3..a3e88c723c26 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_shipping_settings_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_shipping_settings_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_accounts_v1beta.types import shippingsettings +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ShippingSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ShippingSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2366,10 +2416,14 @@ def test_get_shipping_settings_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ShippingSettingsServiceRestInterceptor, "post_get_shipping_settings" ) as post, mock.patch.object( + transports.ShippingSettingsServiceRestInterceptor, + "post_get_shipping_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ShippingSettingsServiceRestInterceptor, "pre_get_shipping_settings" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = shippingsettings.GetShippingSettingsRequest.pb( shippingsettings.GetShippingSettingsRequest() ) @@ -2395,6 +2449,7 @@ def test_get_shipping_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = shippingsettings.ShippingSettings() + post_with_metadata.return_value = shippingsettings.ShippingSettings(), metadata client.get_shipping_settings( request, @@ -2406,6 +2461,7 @@ def test_get_shipping_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_shipping_settings_rest_bad_request( @@ -2710,11 +2766,15 @@ def test_insert_shipping_settings_rest_interceptors(null_interceptor): transports.ShippingSettingsServiceRestInterceptor, "post_insert_shipping_settings", ) as post, mock.patch.object( + transports.ShippingSettingsServiceRestInterceptor, + "post_insert_shipping_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ShippingSettingsServiceRestInterceptor, "pre_insert_shipping_settings", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = shippingsettings.InsertShippingSettingsRequest.pb( shippingsettings.InsertShippingSettingsRequest() ) @@ -2740,6 +2800,7 @@ def test_insert_shipping_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = shippingsettings.ShippingSettings() + post_with_metadata.return_value = shippingsettings.ShippingSettings(), metadata client.insert_shipping_settings( request, @@ -2751,6 +2812,7 @@ def test_insert_shipping_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_agreement_state_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_agreement_state_service.py index e4d378bac349..94cf7d3342b7 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_agreement_state_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_agreement_state_service.py @@ -62,6 +62,13 @@ termsofservicekind, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -355,6 +362,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TermsOfServiceAgreementStateServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TermsOfServiceAgreementStateServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2669,11 +2719,15 @@ def test_get_terms_of_service_agreement_state_rest_interceptors(null_interceptor transports.TermsOfServiceAgreementStateServiceRestInterceptor, "post_get_terms_of_service_agreement_state", ) as post, mock.patch.object( + transports.TermsOfServiceAgreementStateServiceRestInterceptor, + "post_get_terms_of_service_agreement_state_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.TermsOfServiceAgreementStateServiceRestInterceptor, "pre_get_terms_of_service_agreement_state", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( termsofserviceagreementstate.GetTermsOfServiceAgreementStateRequest.pb( termsofserviceagreementstate.GetTermsOfServiceAgreementStateRequest() @@ -2703,6 +2757,10 @@ def test_get_terms_of_service_agreement_state_rest_interceptors(null_interceptor ] pre.return_value = request, metadata post.return_value = termsofserviceagreementstate.TermsOfServiceAgreementState() + post_with_metadata.return_value = ( + termsofserviceagreementstate.TermsOfServiceAgreementState(), + metadata, + ) client.get_terms_of_service_agreement_state( request, @@ -2714,6 +2772,7 @@ def test_get_terms_of_service_agreement_state_rest_interceptors(null_interceptor pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_retrieve_for_application_terms_of_service_agreement_state_rest_bad_request( @@ -2816,11 +2875,15 @@ def test_retrieve_for_application_terms_of_service_agreement_state_rest_intercep transports.TermsOfServiceAgreementStateServiceRestInterceptor, "post_retrieve_for_application_terms_of_service_agreement_state", ) as post, mock.patch.object( + transports.TermsOfServiceAgreementStateServiceRestInterceptor, + "post_retrieve_for_application_terms_of_service_agreement_state_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.TermsOfServiceAgreementStateServiceRestInterceptor, "pre_retrieve_for_application_terms_of_service_agreement_state", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = termsofserviceagreementstate.RetrieveForApplicationTermsOfServiceAgreementStateRequest.pb( termsofserviceagreementstate.RetrieveForApplicationTermsOfServiceAgreementStateRequest() ) @@ -2850,6 +2913,10 @@ def test_retrieve_for_application_terms_of_service_agreement_state_rest_intercep ] pre.return_value = request, metadata post.return_value = termsofserviceagreementstate.TermsOfServiceAgreementState() + post_with_metadata.return_value = ( + termsofserviceagreementstate.TermsOfServiceAgreementState(), + metadata, + ) client.retrieve_for_application_terms_of_service_agreement_state( request, @@ -2861,6 +2928,7 @@ def test_retrieve_for_application_terms_of_service_agreement_state_rest_intercep pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_service.py index 4ef61688bdb6..aae3a2197d6f 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_terms_of_service_service.py @@ -62,6 +62,13 @@ termsofservicekind, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TermsOfServiceServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TermsOfServiceServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2964,10 +3014,14 @@ def test_get_terms_of_service_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TermsOfServiceServiceRestInterceptor, "post_get_terms_of_service" ) as post, mock.patch.object( + transports.TermsOfServiceServiceRestInterceptor, + "post_get_terms_of_service_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.TermsOfServiceServiceRestInterceptor, "pre_get_terms_of_service" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = termsofservice.GetTermsOfServiceRequest.pb( termsofservice.GetTermsOfServiceRequest() ) @@ -2993,6 +3047,7 @@ def test_get_terms_of_service_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = termsofservice.TermsOfService() + post_with_metadata.return_value = termsofservice.TermsOfService(), metadata client.get_terms_of_service( request, @@ -3004,6 +3059,7 @@ def test_get_terms_of_service_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_retrieve_latest_terms_of_service_rest_bad_request( @@ -3097,11 +3153,15 @@ def test_retrieve_latest_terms_of_service_rest_interceptors(null_interceptor): transports.TermsOfServiceServiceRestInterceptor, "post_retrieve_latest_terms_of_service", ) as post, mock.patch.object( + transports.TermsOfServiceServiceRestInterceptor, + "post_retrieve_latest_terms_of_service_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.TermsOfServiceServiceRestInterceptor, "pre_retrieve_latest_terms_of_service", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = termsofservice.RetrieveLatestTermsOfServiceRequest.pb( termsofservice.RetrieveLatestTermsOfServiceRequest() ) @@ -3127,6 +3187,7 @@ def test_retrieve_latest_terms_of_service_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = termsofservice.TermsOfService() + post_with_metadata.return_value = termsofservice.TermsOfService(), metadata client.retrieve_latest_terms_of_service( request, @@ -3138,6 +3199,7 @@ def test_retrieve_latest_terms_of_service_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_accept_terms_of_service_rest_bad_request( diff --git a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_user_service.py b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_user_service.py index 79b7be920ccc..c57dd00773c1 100644 --- a/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_user_service.py +++ b/packages/google-shopping-merchant-accounts/tests/unit/gapic/merchant_accounts_v1beta/test_user_service.py @@ -63,6 +63,13 @@ from google.shopping.merchant_accounts_v1beta.types import user from google.shopping.merchant_accounts_v1beta.types import user as gsma_user +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -302,6 +309,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = UserServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = UserServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4286,10 +4336,13 @@ def test_get_user_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserServiceRestInterceptor, "post_get_user" ) as post, mock.patch.object( + transports.UserServiceRestInterceptor, "post_get_user_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.UserServiceRestInterceptor, "pre_get_user" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user.GetUserRequest.pb(user.GetUserRequest()) transcode.return_value = { "method": "post", @@ -4311,6 +4364,7 @@ def test_get_user_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user.User() + post_with_metadata.return_value = user.User(), metadata client.get_user( request, @@ -4322,6 +4376,7 @@ def test_get_user_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_user_rest_bad_request(request_type=gsma_user.CreateUserRequest): @@ -4476,10 +4531,13 @@ def test_create_user_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserServiceRestInterceptor, "post_create_user" ) as post, mock.patch.object( + transports.UserServiceRestInterceptor, "post_create_user_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.UserServiceRestInterceptor, "pre_create_user" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = gsma_user.CreateUserRequest.pb(gsma_user.CreateUserRequest()) transcode.return_value = { "method": "post", @@ -4501,6 +4559,7 @@ def test_create_user_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gsma_user.User() + post_with_metadata.return_value = gsma_user.User(), metadata client.create_user( request, @@ -4512,6 +4571,7 @@ def test_create_user_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_user_rest_bad_request(request_type=user.DeleteUserRequest): @@ -4775,10 +4835,13 @@ def test_update_user_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserServiceRestInterceptor, "post_update_user" ) as post, mock.patch.object( + transports.UserServiceRestInterceptor, "post_update_user_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.UserServiceRestInterceptor, "pre_update_user" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = gsma_user.UpdateUserRequest.pb(gsma_user.UpdateUserRequest()) transcode.return_value = { "method": "post", @@ -4800,6 +4863,7 @@ def test_update_user_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gsma_user.User() + post_with_metadata.return_value = gsma_user.User(), metadata client.update_user( request, @@ -4811,6 +4875,7 @@ def test_update_user_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_users_rest_bad_request(request_type=user.ListUsersRequest): @@ -4893,10 +4958,13 @@ def test_list_users_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserServiceRestInterceptor, "post_list_users" ) as post, mock.patch.object( + transports.UserServiceRestInterceptor, "post_list_users_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.UserServiceRestInterceptor, "pre_list_users" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user.ListUsersRequest.pb(user.ListUsersRequest()) transcode.return_value = { "method": "post", @@ -4918,6 +4986,7 @@ def test_list_users_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user.ListUsersResponse() + post_with_metadata.return_value = user.ListUsersResponse(), metadata client.list_users( request, @@ -4929,6 +4998,7 @@ def test_list_users_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-conversions/README.rst b/packages/google-shopping-merchant-conversions/README.rst index 364b5e32d9eb..2742709384e1 100644 --- a/packages/google-shopping-merchant-conversions/README.rst +++ b/packages/google-shopping-merchant-conversions/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/client.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/client.py index 980bba28a6dc..a1b6c2a3695f 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/client.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -491,6 +493,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/transports/rest.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/transports/rest.py index 93fb6bd34cd2..836c171be9b4 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/transports/rest.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/services/conversion_sources_service/transports/rest.py @@ -139,12 +139,37 @@ def post_create_conversion_source( ) -> conversionsources.ConversionSource: """Post-rpc interceptor for create_conversion_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_conversion_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ConversionSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_create_conversion_source` interceptor runs + before the `post_create_conversion_source_with_metadata` interceptor. """ return response + def post_create_conversion_source_with_metadata( + self, + response: conversionsources.ConversionSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversionsources.ConversionSource, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for create_conversion_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ConversionSourcesService server but before it is returned to user code. + + We recommend only using this `post_create_conversion_source_with_metadata` + interceptor in new development instead of the `post_create_conversion_source` interceptor. + When both interceptors are used, this `post_create_conversion_source_with_metadata` interceptor runs after the + `post_create_conversion_source` interceptor. The (possibly modified) response returned by + `post_create_conversion_source` will be passed to + `post_create_conversion_source_with_metadata`. + """ + return response, metadata + def pre_delete_conversion_source( self, request: conversionsources.DeleteConversionSourceRequest, @@ -180,12 +205,37 @@ def post_get_conversion_source( ) -> conversionsources.ConversionSource: """Post-rpc interceptor for get_conversion_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_conversion_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ConversionSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_get_conversion_source` interceptor runs + before the `post_get_conversion_source_with_metadata` interceptor. """ return response + def post_get_conversion_source_with_metadata( + self, + response: conversionsources.ConversionSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversionsources.ConversionSource, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_conversion_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ConversionSourcesService server but before it is returned to user code. + + We recommend only using this `post_get_conversion_source_with_metadata` + interceptor in new development instead of the `post_get_conversion_source` interceptor. + When both interceptors are used, this `post_get_conversion_source_with_metadata` interceptor runs after the + `post_get_conversion_source` interceptor. The (possibly modified) response returned by + `post_get_conversion_source` will be passed to + `post_get_conversion_source_with_metadata`. + """ + return response, metadata + def pre_list_conversion_sources( self, request: conversionsources.ListConversionSourcesRequest, @@ -206,12 +256,38 @@ def post_list_conversion_sources( ) -> conversionsources.ListConversionSourcesResponse: """Post-rpc interceptor for list_conversion_sources - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_conversion_sources_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ConversionSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_list_conversion_sources` interceptor runs + before the `post_list_conversion_sources_with_metadata` interceptor. """ return response + def post_list_conversion_sources_with_metadata( + self, + response: conversionsources.ListConversionSourcesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversionsources.ListConversionSourcesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_conversion_sources + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ConversionSourcesService server but before it is returned to user code. + + We recommend only using this `post_list_conversion_sources_with_metadata` + interceptor in new development instead of the `post_list_conversion_sources` interceptor. + When both interceptors are used, this `post_list_conversion_sources_with_metadata` interceptor runs after the + `post_list_conversion_sources` interceptor. The (possibly modified) response returned by + `post_list_conversion_sources` will be passed to + `post_list_conversion_sources_with_metadata`. + """ + return response, metadata + def pre_undelete_conversion_source( self, request: conversionsources.UndeleteConversionSourceRequest, @@ -232,12 +308,37 @@ def post_undelete_conversion_source( ) -> conversionsources.ConversionSource: """Post-rpc interceptor for undelete_conversion_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_undelete_conversion_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ConversionSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_undelete_conversion_source` interceptor runs + before the `post_undelete_conversion_source_with_metadata` interceptor. """ return response + def post_undelete_conversion_source_with_metadata( + self, + response: conversionsources.ConversionSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversionsources.ConversionSource, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for undelete_conversion_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ConversionSourcesService server but before it is returned to user code. + + We recommend only using this `post_undelete_conversion_source_with_metadata` + interceptor in new development instead of the `post_undelete_conversion_source` interceptor. + When both interceptors are used, this `post_undelete_conversion_source_with_metadata` interceptor runs after the + `post_undelete_conversion_source` interceptor. The (possibly modified) response returned by + `post_undelete_conversion_source` will be passed to + `post_undelete_conversion_source_with_metadata`. + """ + return response, metadata + def pre_update_conversion_source( self, request: conversionsources.UpdateConversionSourceRequest, @@ -258,12 +359,37 @@ def post_update_conversion_source( ) -> conversionsources.ConversionSource: """Post-rpc interceptor for update_conversion_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_conversion_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ConversionSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_update_conversion_source` interceptor runs + before the `post_update_conversion_source_with_metadata` interceptor. """ return response + def post_update_conversion_source_with_metadata( + self, + response: conversionsources.ConversionSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversionsources.ConversionSource, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_conversion_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ConversionSourcesService server but before it is returned to user code. + + We recommend only using this `post_update_conversion_source_with_metadata` + interceptor in new development instead of the `post_update_conversion_source` interceptor. + When both interceptors are used, this `post_update_conversion_source_with_metadata` interceptor runs after the + `post_update_conversion_source` interceptor. The (possibly modified) response returned by + `post_update_conversion_source` will be passed to + `post_update_conversion_source_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ConversionSourcesServiceRestStub: @@ -483,6 +609,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_conversion_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_conversion_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -743,6 +873,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_conversion_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_conversion_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -891,6 +1025,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_conversion_sources(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_conversion_sources_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1052,6 +1190,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_undelete_conversion_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_undelete_conversion_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1208,6 +1350,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_conversion_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_conversion_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-conversions/noxfile.py b/packages/google-shopping-merchant-conversions/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-conversions/noxfile.py +++ b/packages/google-shopping-merchant-conversions/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json b/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json index 0ff6827002c2..7b979a5c445b 100644 --- a/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json +++ b/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-conversions", - "version": "0.1.6" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-conversions/tests/unit/gapic/merchant_conversions_v1beta/test_conversion_sources_service.py b/packages/google-shopping-merchant-conversions/tests/unit/gapic/merchant_conversions_v1beta/test_conversion_sources_service.py index 740d263c45c6..de082fd729e1 100644 --- a/packages/google-shopping-merchant-conversions/tests/unit/gapic/merchant_conversions_v1beta/test_conversion_sources_service.py +++ b/packages/google-shopping-merchant-conversions/tests/unit/gapic/merchant_conversions_v1beta/test_conversion_sources_service.py @@ -62,6 +62,13 @@ ) from google.shopping.merchant_conversions_v1beta.types import conversionsources +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ConversionSourcesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ConversionSourcesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5167,11 +5217,15 @@ def test_create_conversion_source_rest_interceptors(null_interceptor): transports.ConversionSourcesServiceRestInterceptor, "post_create_conversion_source", ) as post, mock.patch.object( + transports.ConversionSourcesServiceRestInterceptor, + "post_create_conversion_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "pre_create_conversion_source", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = conversionsources.CreateConversionSourceRequest.pb( conversionsources.CreateConversionSourceRequest() ) @@ -5197,6 +5251,7 @@ def test_create_conversion_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = conversionsources.ConversionSource() + post_with_metadata.return_value = conversionsources.ConversionSource(), metadata client.create_conversion_source( request, @@ -5208,6 +5263,7 @@ def test_create_conversion_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_conversion_source_rest_bad_request( @@ -5391,11 +5447,15 @@ def test_update_conversion_source_rest_interceptors(null_interceptor): transports.ConversionSourcesServiceRestInterceptor, "post_update_conversion_source", ) as post, mock.patch.object( + transports.ConversionSourcesServiceRestInterceptor, + "post_update_conversion_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "pre_update_conversion_source", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = conversionsources.UpdateConversionSourceRequest.pb( conversionsources.UpdateConversionSourceRequest() ) @@ -5421,6 +5481,7 @@ def test_update_conversion_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = conversionsources.ConversionSource() + post_with_metadata.return_value = conversionsources.ConversionSource(), metadata client.update_conversion_source( request, @@ -5432,6 +5493,7 @@ def test_update_conversion_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_conversion_source_rest_bad_request( @@ -5631,11 +5693,15 @@ def test_undelete_conversion_source_rest_interceptors(null_interceptor): transports.ConversionSourcesServiceRestInterceptor, "post_undelete_conversion_source", ) as post, mock.patch.object( + transports.ConversionSourcesServiceRestInterceptor, + "post_undelete_conversion_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "pre_undelete_conversion_source", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = conversionsources.UndeleteConversionSourceRequest.pb( conversionsources.UndeleteConversionSourceRequest() ) @@ -5661,6 +5727,7 @@ def test_undelete_conversion_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = conversionsources.ConversionSource() + post_with_metadata.return_value = conversionsources.ConversionSource(), metadata client.undelete_conversion_source( request, @@ -5672,6 +5739,7 @@ def test_undelete_conversion_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_conversion_source_rest_bad_request( @@ -5760,10 +5828,14 @@ def test_get_conversion_source_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "post_get_conversion_source" ) as post, mock.patch.object( + transports.ConversionSourcesServiceRestInterceptor, + "post_get_conversion_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "pre_get_conversion_source" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = conversionsources.GetConversionSourceRequest.pb( conversionsources.GetConversionSourceRequest() ) @@ -5789,6 +5861,7 @@ def test_get_conversion_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = conversionsources.ConversionSource() + post_with_metadata.return_value = conversionsources.ConversionSource(), metadata client.get_conversion_source( request, @@ -5800,6 +5873,7 @@ def test_get_conversion_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_conversion_sources_rest_bad_request( @@ -5885,11 +5959,15 @@ def test_list_conversion_sources_rest_interceptors(null_interceptor): transports.ConversionSourcesServiceRestInterceptor, "post_list_conversion_sources", ) as post, mock.patch.object( + transports.ConversionSourcesServiceRestInterceptor, + "post_list_conversion_sources_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ConversionSourcesServiceRestInterceptor, "pre_list_conversion_sources", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = conversionsources.ListConversionSourcesRequest.pb( conversionsources.ListConversionSourcesRequest() ) @@ -5915,6 +5993,10 @@ def test_list_conversion_sources_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = conversionsources.ListConversionSourcesResponse() + post_with_metadata.return_value = ( + conversionsources.ListConversionSourcesResponse(), + metadata, + ) client.list_conversion_sources( request, @@ -5926,6 +6008,7 @@ def test_list_conversion_sources_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-datasources/README.rst b/packages/google-shopping-merchant-datasources/README.rst index 7340d1d0c7f8..109f4643adc7 100644 --- a/packages/google-shopping-merchant-datasources/README.rst +++ b/packages/google-shopping-merchant-datasources/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/client.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/client.py index e3b7638db779..7fe6d8af4e18 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/client.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -493,6 +495,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/transports/rest.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/transports/rest.py index b523758bc8fb..d87afeb992e7 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/transports/rest.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/data_sources_service/transports/rest.py @@ -134,12 +134,35 @@ def post_create_data_source( ) -> datasources.DataSource: """Post-rpc interceptor for create_data_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_data_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the DataSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_create_data_source` interceptor runs + before the `post_create_data_source_with_metadata` interceptor. """ return response + def post_create_data_source_with_metadata( + self, + response: datasources.DataSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[datasources.DataSource, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_data_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the DataSourcesService server but before it is returned to user code. + + We recommend only using this `post_create_data_source_with_metadata` + interceptor in new development instead of the `post_create_data_source` interceptor. + When both interceptors are used, this `post_create_data_source_with_metadata` interceptor runs after the + `post_create_data_source` interceptor. The (possibly modified) response returned by + `post_create_data_source` will be passed to + `post_create_data_source_with_metadata`. + """ + return response, metadata + def pre_delete_data_source( self, request: datasources.DeleteDataSourceRequest, @@ -187,12 +210,35 @@ def post_get_data_source( ) -> datasources.DataSource: """Post-rpc interceptor for get_data_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_data_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the DataSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_get_data_source` interceptor runs + before the `post_get_data_source_with_metadata` interceptor. """ return response + def post_get_data_source_with_metadata( + self, + response: datasources.DataSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[datasources.DataSource, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_data_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the DataSourcesService server but before it is returned to user code. + + We recommend only using this `post_get_data_source_with_metadata` + interceptor in new development instead of the `post_get_data_source` interceptor. + When both interceptors are used, this `post_get_data_source_with_metadata` interceptor runs after the + `post_get_data_source` interceptor. The (possibly modified) response returned by + `post_get_data_source` will be passed to + `post_get_data_source_with_metadata`. + """ + return response, metadata + def pre_list_data_sources( self, request: datasources.ListDataSourcesRequest, @@ -212,12 +258,37 @@ def post_list_data_sources( ) -> datasources.ListDataSourcesResponse: """Post-rpc interceptor for list_data_sources - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_data_sources_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the DataSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_list_data_sources` interceptor runs + before the `post_list_data_sources_with_metadata` interceptor. """ return response + def post_list_data_sources_with_metadata( + self, + response: datasources.ListDataSourcesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + datasources.ListDataSourcesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_data_sources + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the DataSourcesService server but before it is returned to user code. + + We recommend only using this `post_list_data_sources_with_metadata` + interceptor in new development instead of the `post_list_data_sources` interceptor. + When both interceptors are used, this `post_list_data_sources_with_metadata` interceptor runs after the + `post_list_data_sources` interceptor. The (possibly modified) response returned by + `post_list_data_sources` will be passed to + `post_list_data_sources_with_metadata`. + """ + return response, metadata + def pre_update_data_source( self, request: datasources.UpdateDataSourceRequest, @@ -237,12 +308,35 @@ def post_update_data_source( ) -> datasources.DataSource: """Post-rpc interceptor for update_data_source - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_data_source_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the DataSourcesService server but before - it is returned to user code. + it is returned to user code. This `post_update_data_source` interceptor runs + before the `post_update_data_source_with_metadata` interceptor. """ return response + def post_update_data_source_with_metadata( + self, + response: datasources.DataSource, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[datasources.DataSource, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_data_source + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the DataSourcesService server but before it is returned to user code. + + We recommend only using this `post_update_data_source_with_metadata` + interceptor in new development instead of the `post_update_data_source` interceptor. + When both interceptors are used, this `post_update_data_source_with_metadata` interceptor runs after the + `post_update_data_source` interceptor. The (possibly modified) response returned by + `post_update_data_source` will be passed to + `post_update_data_source_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class DataSourcesServiceRestStub: @@ -463,6 +557,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_data_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_data_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -834,6 +932,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_data_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_data_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -980,6 +1082,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_data_sources(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_data_sources_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1135,6 +1241,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_data_source(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_data_source_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/client.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/client.py index 370ed30093ca..df5049aabdcc 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/client.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -485,6 +487,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/transports/rest.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/transports/rest.py index 2619a225f56a..7e00e54887a8 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/transports/rest.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/services/file_uploads_service/transports/rest.py @@ -101,12 +101,35 @@ def post_get_file_upload( ) -> fileuploads.FileUpload: """Post-rpc interceptor for get_file_upload - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_file_upload_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the FileUploadsService server but before - it is returned to user code. + it is returned to user code. This `post_get_file_upload` interceptor runs + before the `post_get_file_upload_with_metadata` interceptor. """ return response + def post_get_file_upload_with_metadata( + self, + response: fileuploads.FileUpload, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[fileuploads.FileUpload, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_file_upload + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the FileUploadsService server but before it is returned to user code. + + We recommend only using this `post_get_file_upload_with_metadata` + interceptor in new development instead of the `post_get_file_upload` interceptor. + When both interceptors are used, this `post_get_file_upload_with_metadata` interceptor runs after the + `post_get_file_upload` interceptor. The (possibly modified) response returned by + `post_get_file_upload` will be passed to + `post_get_file_upload_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class FileUploadsServiceRestStub: @@ -320,6 +343,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_file_upload(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_file_upload_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-datasources/noxfile.py b/packages/google-shopping-merchant-datasources/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-datasources/noxfile.py +++ b/packages/google-shopping-merchant-datasources/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json b/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json index 7bc53136b90a..992de0dc6fb0 100644 --- a/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json +++ b/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-datasources", - "version": "0.1.7" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_data_sources_service.py b/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_data_sources_service.py index ffaf6156a097..d3ef1be09556 100644 --- a/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_data_sources_service.py +++ b/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_data_sources_service.py @@ -67,6 +67,13 @@ fileinputs, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = DataSourcesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = DataSourcesServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4987,10 +5037,14 @@ def test_get_data_source_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "post_get_data_source" ) as post, mock.patch.object( + transports.DataSourcesServiceRestInterceptor, + "post_get_data_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "pre_get_data_source" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = datasources.GetDataSourceRequest.pb( datasources.GetDataSourceRequest() ) @@ -5014,6 +5068,7 @@ def test_get_data_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = datasources.DataSource() + post_with_metadata.return_value = datasources.DataSource(), metadata client.get_data_source( request, @@ -5025,6 +5080,7 @@ def test_get_data_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_data_sources_rest_bad_request( @@ -5109,10 +5165,14 @@ def test_list_data_sources_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "post_list_data_sources" ) as post, mock.patch.object( + transports.DataSourcesServiceRestInterceptor, + "post_list_data_sources_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "pre_list_data_sources" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = datasources.ListDataSourcesRequest.pb( datasources.ListDataSourcesRequest() ) @@ -5138,6 +5198,10 @@ def test_list_data_sources_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = datasources.ListDataSourcesResponse() + post_with_metadata.return_value = ( + datasources.ListDataSourcesResponse(), + metadata, + ) client.list_data_sources( request, @@ -5149,6 +5213,7 @@ def test_list_data_sources_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_data_source_rest_bad_request( @@ -5366,10 +5431,14 @@ def test_create_data_source_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "post_create_data_source" ) as post, mock.patch.object( + transports.DataSourcesServiceRestInterceptor, + "post_create_data_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "pre_create_data_source" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = datasources.CreateDataSourceRequest.pb( datasources.CreateDataSourceRequest() ) @@ -5393,6 +5462,7 @@ def test_create_data_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = datasources.DataSource() + post_with_metadata.return_value = datasources.DataSource(), metadata client.create_data_source( request, @@ -5404,6 +5474,7 @@ def test_create_data_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_data_source_rest_bad_request( @@ -5621,10 +5692,14 @@ def test_update_data_source_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "post_update_data_source" ) as post, mock.patch.object( + transports.DataSourcesServiceRestInterceptor, + "post_update_data_source_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.DataSourcesServiceRestInterceptor, "pre_update_data_source" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = datasources.UpdateDataSourceRequest.pb( datasources.UpdateDataSourceRequest() ) @@ -5648,6 +5723,7 @@ def test_update_data_source_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = datasources.DataSource() + post_with_metadata.return_value = datasources.DataSource(), metadata client.update_data_source( request, @@ -5659,6 +5735,7 @@ def test_update_data_source_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_data_source_rest_bad_request( diff --git a/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_file_uploads_service.py b/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_file_uploads_service.py index 1d9ea6845d70..ee1261afc608 100644 --- a/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_file_uploads_service.py +++ b/packages/google-shopping-merchant-datasources/tests/unit/gapic/merchant_datasources_v1beta/test_file_uploads_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_datasources_v1beta.types import fileuploads +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -331,6 +338,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = FileUploadsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = FileUploadsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1897,10 +1947,14 @@ def test_get_file_upload_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FileUploadsServiceRestInterceptor, "post_get_file_upload" ) as post, mock.patch.object( + transports.FileUploadsServiceRestInterceptor, + "post_get_file_upload_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.FileUploadsServiceRestInterceptor, "pre_get_file_upload" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = fileuploads.GetFileUploadRequest.pb( fileuploads.GetFileUploadRequest() ) @@ -1924,6 +1978,7 @@ def test_get_file_upload_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = fileuploads.FileUpload() + post_with_metadata.return_value = fileuploads.FileUpload(), metadata client.get_file_upload( request, @@ -1935,6 +1990,7 @@ def test_get_file_upload_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-inventories/README.rst b/packages/google-shopping-merchant-inventories/README.rst index 7bc48747e84a..e153c1a56249 100644 --- a/packages/google-shopping-merchant-inventories/README.rst +++ b/packages/google-shopping-merchant-inventories/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant Inventories API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant Inventories API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/client.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/client.py index 29fa40212482..6af582ce2f5b 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/client.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -491,6 +493,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/transports/rest.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/transports/rest.py index 30a453c86e38..2d2f733d3862 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/transports/rest.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/local_inventory_service/transports/rest.py @@ -130,12 +130,35 @@ def post_insert_local_inventory( ) -> localinventory.LocalInventory: """Post-rpc interceptor for insert_local_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_local_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LocalInventoryService server but before - it is returned to user code. + it is returned to user code. This `post_insert_local_inventory` interceptor runs + before the `post_insert_local_inventory_with_metadata` interceptor. """ return response + def post_insert_local_inventory_with_metadata( + self, + response: localinventory.LocalInventory, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[localinventory.LocalInventory, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_local_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LocalInventoryService server but before it is returned to user code. + + We recommend only using this `post_insert_local_inventory_with_metadata` + interceptor in new development instead of the `post_insert_local_inventory` interceptor. + When both interceptors are used, this `post_insert_local_inventory_with_metadata` interceptor runs after the + `post_insert_local_inventory` interceptor. The (possibly modified) response returned by + `post_insert_local_inventory` will be passed to + `post_insert_local_inventory_with_metadata`. + """ + return response, metadata + def pre_list_local_inventories( self, request: localinventory.ListLocalInventoriesRequest, @@ -156,12 +179,38 @@ def post_list_local_inventories( ) -> localinventory.ListLocalInventoriesResponse: """Post-rpc interceptor for list_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LocalInventoryService server but before - it is returned to user code. + it is returned to user code. This `post_list_local_inventories` interceptor runs + before the `post_list_local_inventories_with_metadata` interceptor. """ return response + def post_list_local_inventories_with_metadata( + self, + response: localinventory.ListLocalInventoriesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + localinventory.ListLocalInventoriesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LocalInventoryService server but before it is returned to user code. + + We recommend only using this `post_list_local_inventories_with_metadata` + interceptor in new development instead of the `post_list_local_inventories` interceptor. + When both interceptors are used, this `post_list_local_inventories_with_metadata` interceptor runs after the + `post_list_local_inventories` interceptor. The (possibly modified) response returned by + `post_list_local_inventories` will be passed to + `post_list_local_inventories_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class LocalInventoryServiceRestStub: @@ -495,6 +544,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_local_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_local_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -642,6 +695,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/client.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/client.py index 907abc8f8165..1fceec7271a8 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/client.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -495,6 +497,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/transports/rest.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/transports/rest.py index e03a5e4fa4ec..44695ff0d876 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/transports/rest.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/services/regional_inventory_service/transports/rest.py @@ -130,12 +130,37 @@ def post_insert_regional_inventory( ) -> regionalinventory.RegionalInventory: """Post-rpc interceptor for insert_regional_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_regional_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionalInventoryService server but before - it is returned to user code. + it is returned to user code. This `post_insert_regional_inventory` interceptor runs + before the `post_insert_regional_inventory_with_metadata` interceptor. """ return response + def post_insert_regional_inventory_with_metadata( + self, + response: regionalinventory.RegionalInventory, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + regionalinventory.RegionalInventory, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for insert_regional_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionalInventoryService server but before it is returned to user code. + + We recommend only using this `post_insert_regional_inventory_with_metadata` + interceptor in new development instead of the `post_insert_regional_inventory` interceptor. + When both interceptors are used, this `post_insert_regional_inventory_with_metadata` interceptor runs after the + `post_insert_regional_inventory` interceptor. The (possibly modified) response returned by + `post_insert_regional_inventory` will be passed to + `post_insert_regional_inventory_with_metadata`. + """ + return response, metadata + def pre_list_regional_inventories( self, request: regionalinventory.ListRegionalInventoriesRequest, @@ -156,12 +181,38 @@ def post_list_regional_inventories( ) -> regionalinventory.ListRegionalInventoriesResponse: """Post-rpc interceptor for list_regional_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_regional_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RegionalInventoryService server but before - it is returned to user code. + it is returned to user code. This `post_list_regional_inventories` interceptor runs + before the `post_list_regional_inventories_with_metadata` interceptor. """ return response + def post_list_regional_inventories_with_metadata( + self, + response: regionalinventory.ListRegionalInventoriesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + regionalinventory.ListRegionalInventoriesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_regional_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RegionalInventoryService server but before it is returned to user code. + + We recommend only using this `post_list_regional_inventories_with_metadata` + interceptor in new development instead of the `post_list_regional_inventories` interceptor. + When both interceptors are used, this `post_list_regional_inventories_with_metadata` interceptor runs after the + `post_list_regional_inventories` interceptor. The (possibly modified) response returned by + `post_list_regional_inventories` will be passed to + `post_list_regional_inventories_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class RegionalInventoryServiceRestStub: @@ -494,6 +545,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_regional_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_regional_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -642,6 +697,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_regional_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_regional_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-inventories/noxfile.py b/packages/google-shopping-merchant-inventories/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-inventories/noxfile.py +++ b/packages/google-shopping-merchant-inventories/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json b/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json index fdaeed26cae6..73ddfcf94070 100644 --- a/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json +++ b/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-inventories", - "version": "0.1.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_local_inventory_service.py b/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_local_inventory_service.py index 12a25e57fe34..9f732e608e84 100644 --- a/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_local_inventory_service.py +++ b/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_local_inventory_service.py @@ -63,6 +63,13 @@ ) from google.shopping.merchant_inventories_v1beta.types import localinventory +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = LocalInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = LocalInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3231,10 +3281,14 @@ def test_list_local_inventories_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LocalInventoryServiceRestInterceptor, "post_list_local_inventories" ) as post, mock.patch.object( + transports.LocalInventoryServiceRestInterceptor, + "post_list_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.LocalInventoryServiceRestInterceptor, "pre_list_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = localinventory.ListLocalInventoriesRequest.pb( localinventory.ListLocalInventoriesRequest() ) @@ -3260,6 +3314,10 @@ def test_list_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = localinventory.ListLocalInventoriesResponse() + post_with_metadata.return_value = ( + localinventory.ListLocalInventoriesResponse(), + metadata, + ) client.list_local_inventories( request, @@ -3271,6 +3329,7 @@ def test_list_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_local_inventory_rest_bad_request( @@ -3457,10 +3516,14 @@ def test_insert_local_inventory_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LocalInventoryServiceRestInterceptor, "post_insert_local_inventory" ) as post, mock.patch.object( + transports.LocalInventoryServiceRestInterceptor, + "post_insert_local_inventory_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.LocalInventoryServiceRestInterceptor, "pre_insert_local_inventory" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = localinventory.InsertLocalInventoryRequest.pb( localinventory.InsertLocalInventoryRequest() ) @@ -3486,6 +3549,7 @@ def test_insert_local_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = localinventory.LocalInventory() + post_with_metadata.return_value = localinventory.LocalInventory(), metadata client.insert_local_inventory( request, @@ -3497,6 +3561,7 @@ def test_insert_local_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_local_inventory_rest_bad_request( diff --git a/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_regional_inventory_service.py b/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_regional_inventory_service.py index ca08ede3303e..3aa4c9eca369 100644 --- a/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_regional_inventory_service.py +++ b/packages/google-shopping-merchant-inventories/tests/unit/gapic/merchant_inventories_v1beta/test_regional_inventory_service.py @@ -63,6 +63,13 @@ ) from google.shopping.merchant_inventories_v1beta.types import regionalinventory +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RegionalInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RegionalInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3231,11 +3281,15 @@ def test_list_regional_inventories_rest_interceptors(null_interceptor): transports.RegionalInventoryServiceRestInterceptor, "post_list_regional_inventories", ) as post, mock.patch.object( + transports.RegionalInventoryServiceRestInterceptor, + "post_list_regional_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RegionalInventoryServiceRestInterceptor, "pre_list_regional_inventories", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regionalinventory.ListRegionalInventoriesRequest.pb( regionalinventory.ListRegionalInventoriesRequest() ) @@ -3261,6 +3315,10 @@ def test_list_regional_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regionalinventory.ListRegionalInventoriesResponse() + post_with_metadata.return_value = ( + regionalinventory.ListRegionalInventoriesResponse(), + metadata, + ) client.list_regional_inventories( request, @@ -3272,6 +3330,7 @@ def test_list_regional_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_regional_inventory_rest_bad_request( @@ -3447,11 +3506,15 @@ def test_insert_regional_inventory_rest_interceptors(null_interceptor): transports.RegionalInventoryServiceRestInterceptor, "post_insert_regional_inventory", ) as post, mock.patch.object( + transports.RegionalInventoryServiceRestInterceptor, + "post_insert_regional_inventory_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RegionalInventoryServiceRestInterceptor, "pre_insert_regional_inventory", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = regionalinventory.InsertRegionalInventoryRequest.pb( regionalinventory.InsertRegionalInventoryRequest() ) @@ -3477,6 +3540,10 @@ def test_insert_regional_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = regionalinventory.RegionalInventory() + post_with_metadata.return_value = ( + regionalinventory.RegionalInventory(), + metadata, + ) client.insert_regional_inventory( request, @@ -3488,6 +3555,7 @@ def test_insert_regional_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_regional_inventory_rest_bad_request( diff --git a/packages/google-shopping-merchant-lfp/README.rst b/packages/google-shopping-merchant-lfp/README.rst index 0dcac907c973..c8445277325e 100644 --- a/packages/google-shopping-merchant-lfp/README.rst +++ b/packages/google-shopping-merchant-lfp/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/client.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/client.py index 08c5e1569a61..b708572cca6c 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/client.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -491,6 +493,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/transports/rest.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/transports/rest.py index 3db7ac1e849a..57d62f120853 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/transports/rest.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_inventory_service/transports/rest.py @@ -101,12 +101,35 @@ def post_insert_lfp_inventory( ) -> lfpinventory.LfpInventory: """Post-rpc interceptor for insert_lfp_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_lfp_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LfpInventoryService server but before - it is returned to user code. + it is returned to user code. This `post_insert_lfp_inventory` interceptor runs + before the `post_insert_lfp_inventory_with_metadata` interceptor. """ return response + def post_insert_lfp_inventory_with_metadata( + self, + response: lfpinventory.LfpInventory, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[lfpinventory.LfpInventory, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_lfp_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LfpInventoryService server but before it is returned to user code. + + We recommend only using this `post_insert_lfp_inventory_with_metadata` + interceptor in new development instead of the `post_insert_lfp_inventory` interceptor. + When both interceptors are used, this `post_insert_lfp_inventory_with_metadata` interceptor runs after the + `post_insert_lfp_inventory` interceptor. The (possibly modified) response returned by + `post_insert_lfp_inventory` will be passed to + `post_insert_lfp_inventory_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class LfpInventoryServiceRestStub: @@ -324,6 +347,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_lfp_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_lfp_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/client.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/client.py index ffc314249a51..2530c4bbcf00 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/client.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -484,6 +486,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/transports/rest.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/transports/rest.py index e80adff4996a..d6e3402f344f 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/transports/rest.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_sale_service/transports/rest.py @@ -97,12 +97,35 @@ def pre_insert_lfp_sale( def post_insert_lfp_sale(self, response: lfpsale.LfpSale) -> lfpsale.LfpSale: """Post-rpc interceptor for insert_lfp_sale - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_lfp_sale_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LfpSaleService server but before - it is returned to user code. + it is returned to user code. This `post_insert_lfp_sale` interceptor runs + before the `post_insert_lfp_sale_with_metadata` interceptor. """ return response + def post_insert_lfp_sale_with_metadata( + self, + response: lfpsale.LfpSale, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[lfpsale.LfpSale, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_lfp_sale + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LfpSaleService server but before it is returned to user code. + + We recommend only using this `post_insert_lfp_sale_with_metadata` + interceptor in new development instead of the `post_insert_lfp_sale` interceptor. + When both interceptors are used, this `post_insert_lfp_sale_with_metadata` interceptor runs after the + `post_insert_lfp_sale` interceptor. The (possibly modified) response returned by + `post_insert_lfp_sale` will be passed to + `post_insert_lfp_sale_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class LfpSaleServiceRestStub: @@ -316,6 +339,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_lfp_sale(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_lfp_sale_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/client.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/client.py index 8cfbe2326013..252724df7cce 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/client.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -487,6 +489,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/transports/rest.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/transports/rest.py index c9ef2b40314b..15c7ea119c70 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/transports/rest.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/services/lfp_store_service/transports/rest.py @@ -130,12 +130,35 @@ def pre_get_lfp_store( def post_get_lfp_store(self, response: lfpstore.LfpStore) -> lfpstore.LfpStore: """Post-rpc interceptor for get_lfp_store - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_lfp_store_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LfpStoreService server but before - it is returned to user code. + it is returned to user code. This `post_get_lfp_store` interceptor runs + before the `post_get_lfp_store_with_metadata` interceptor. """ return response + def post_get_lfp_store_with_metadata( + self, + response: lfpstore.LfpStore, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[lfpstore.LfpStore, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_lfp_store + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LfpStoreService server but before it is returned to user code. + + We recommend only using this `post_get_lfp_store_with_metadata` + interceptor in new development instead of the `post_get_lfp_store` interceptor. + When both interceptors are used, this `post_get_lfp_store_with_metadata` interceptor runs after the + `post_get_lfp_store` interceptor. The (possibly modified) response returned by + `post_get_lfp_store` will be passed to + `post_get_lfp_store_with_metadata`. + """ + return response, metadata + def pre_insert_lfp_store( self, request: lfpstore.InsertLfpStoreRequest, @@ -151,12 +174,35 @@ def pre_insert_lfp_store( def post_insert_lfp_store(self, response: lfpstore.LfpStore) -> lfpstore.LfpStore: """Post-rpc interceptor for insert_lfp_store - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_lfp_store_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LfpStoreService server but before - it is returned to user code. + it is returned to user code. This `post_insert_lfp_store` interceptor runs + before the `post_insert_lfp_store_with_metadata` interceptor. """ return response + def post_insert_lfp_store_with_metadata( + self, + response: lfpstore.LfpStore, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[lfpstore.LfpStore, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_lfp_store + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LfpStoreService server but before it is returned to user code. + + We recommend only using this `post_insert_lfp_store_with_metadata` + interceptor in new development instead of the `post_insert_lfp_store` interceptor. + When both interceptors are used, this `post_insert_lfp_store_with_metadata` interceptor runs after the + `post_insert_lfp_store` interceptor. The (possibly modified) response returned by + `post_insert_lfp_store` will be passed to + `post_insert_lfp_store_with_metadata`. + """ + return response, metadata + def pre_list_lfp_stores( self, request: lfpstore.ListLfpStoresRequest, @@ -174,12 +220,35 @@ def post_list_lfp_stores( ) -> lfpstore.ListLfpStoresResponse: """Post-rpc interceptor for list_lfp_stores - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_lfp_stores_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the LfpStoreService server but before - it is returned to user code. + it is returned to user code. This `post_list_lfp_stores` interceptor runs + before the `post_list_lfp_stores_with_metadata` interceptor. """ return response + def post_list_lfp_stores_with_metadata( + self, + response: lfpstore.ListLfpStoresResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[lfpstore.ListLfpStoresResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_lfp_stores + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the LfpStoreService server but before it is returned to user code. + + We recommend only using this `post_list_lfp_stores_with_metadata` + interceptor in new development instead of the `post_list_lfp_stores` interceptor. + When both interceptors are used, this `post_list_lfp_stores_with_metadata` interceptor runs after the + `post_list_lfp_stores` interceptor. The (possibly modified) response returned by + `post_list_lfp_stores` will be passed to + `post_list_lfp_stores_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class LfpStoreServiceRestStub: @@ -502,6 +571,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_lfp_store(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_lfp_store_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -658,6 +731,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_lfp_store(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_lfp_store_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -801,6 +878,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_lfp_stores(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_lfp_stores_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-lfp/noxfile.py b/packages/google-shopping-merchant-lfp/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-lfp/noxfile.py +++ b/packages/google-shopping-merchant-lfp/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json b/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json index c5d7fad839b1..c88051dded42 100644 --- a/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json +++ b/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-lfp", - "version": "0.1.6" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_inventory_service.py b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_inventory_service.py index b5cd41e83d0e..e4ac428e0207 100644 --- a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_inventory_service.py +++ b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_inventory_service.py @@ -61,6 +61,13 @@ ) from google.shopping.merchant_lfp_v1beta.types import lfpinventory +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -334,6 +341,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = LfpInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = LfpInventoryServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1930,10 +1980,14 @@ def test_insert_lfp_inventory_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LfpInventoryServiceRestInterceptor, "post_insert_lfp_inventory" ) as post, mock.patch.object( + transports.LfpInventoryServiceRestInterceptor, + "post_insert_lfp_inventory_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.LfpInventoryServiceRestInterceptor, "pre_insert_lfp_inventory" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = lfpinventory.InsertLfpInventoryRequest.pb( lfpinventory.InsertLfpInventoryRequest() ) @@ -1957,6 +2011,7 @@ def test_insert_lfp_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = lfpinventory.LfpInventory() + post_with_metadata.return_value = lfpinventory.LfpInventory(), metadata client.insert_lfp_inventory( request, @@ -1968,6 +2023,7 @@ def test_insert_lfp_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_sale_service.py b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_sale_service.py index 4e59cae51f72..684551ff6f67 100644 --- a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_sale_service.py +++ b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_sale_service.py @@ -61,6 +61,13 @@ ) from google.shopping.merchant_lfp_v1beta.types import lfpsale +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = LfpSaleServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = LfpSaleServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1832,10 +1882,13 @@ def test_insert_lfp_sale_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LfpSaleServiceRestInterceptor, "post_insert_lfp_sale" ) as post, mock.patch.object( + transports.LfpSaleServiceRestInterceptor, "post_insert_lfp_sale_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.LfpSaleServiceRestInterceptor, "pre_insert_lfp_sale" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = lfpsale.InsertLfpSaleRequest.pb(lfpsale.InsertLfpSaleRequest()) transcode.return_value = { "method": "post", @@ -1857,6 +1910,7 @@ def test_insert_lfp_sale_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = lfpsale.LfpSale() + post_with_metadata.return_value = lfpsale.LfpSale(), metadata client.insert_lfp_sale( request, @@ -1868,6 +1922,7 @@ def test_insert_lfp_sale_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_store_service.py b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_store_service.py index 69f3e26da8b8..3e3358f97e08 100644 --- a/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_store_service.py +++ b/packages/google-shopping-merchant-lfp/tests/unit/gapic/merchant_lfp_v1beta/test_lfp_store_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_lfp_v1beta.types import lfpstore +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -318,6 +325,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = LfpStoreServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = LfpStoreServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3909,10 +3959,13 @@ def test_get_lfp_store_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "post_get_lfp_store" ) as post, mock.patch.object( + transports.LfpStoreServiceRestInterceptor, "post_get_lfp_store_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "pre_get_lfp_store" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = lfpstore.GetLfpStoreRequest.pb(lfpstore.GetLfpStoreRequest()) transcode.return_value = { "method": "post", @@ -3934,6 +3987,7 @@ def test_get_lfp_store_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = lfpstore.LfpStore() + post_with_metadata.return_value = lfpstore.LfpStore(), metadata client.get_lfp_store( request, @@ -3945,6 +3999,7 @@ def test_get_lfp_store_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_lfp_store_rest_bad_request(request_type=lfpstore.InsertLfpStoreRequest): @@ -4130,10 +4185,13 @@ def test_insert_lfp_store_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "post_insert_lfp_store" ) as post, mock.patch.object( + transports.LfpStoreServiceRestInterceptor, "post_insert_lfp_store_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "pre_insert_lfp_store" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = lfpstore.InsertLfpStoreRequest.pb(lfpstore.InsertLfpStoreRequest()) transcode.return_value = { "method": "post", @@ -4155,6 +4213,7 @@ def test_insert_lfp_store_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = lfpstore.LfpStore() + post_with_metadata.return_value = lfpstore.LfpStore(), metadata client.insert_lfp_store( request, @@ -4166,6 +4225,7 @@ def test_insert_lfp_store_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_lfp_store_rest_bad_request(request_type=lfpstore.DeleteLfpStoreRequest): @@ -4353,10 +4413,13 @@ def test_list_lfp_stores_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "post_list_lfp_stores" ) as post, mock.patch.object( + transports.LfpStoreServiceRestInterceptor, "post_list_lfp_stores_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.LfpStoreServiceRestInterceptor, "pre_list_lfp_stores" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = lfpstore.ListLfpStoresRequest.pb(lfpstore.ListLfpStoresRequest()) transcode.return_value = { "method": "post", @@ -4380,6 +4443,7 @@ def test_list_lfp_stores_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = lfpstore.ListLfpStoresResponse() + post_with_metadata.return_value = lfpstore.ListLfpStoresResponse(), metadata client.list_lfp_stores( request, @@ -4391,6 +4455,7 @@ def test_list_lfp_stores_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-notifications/README.rst b/packages/google-shopping-merchant-notifications/README.rst index ecfb067709a7..27607fa20a29 100644 --- a/packages/google-shopping-merchant-notifications/README.rst +++ b/packages/google-shopping-merchant-notifications/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/client.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/client.py index a19c1a2b6a62..b265a6fa1ae5 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/client.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/transports/rest.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/transports/rest.py index 5eedb5916c07..94911916372c 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/transports/rest.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/services/notifications_api_service/transports/rest.py @@ -131,12 +131,38 @@ def post_create_notification_subscription( ) -> notificationsapi.NotificationSubscription: """Post-rpc interceptor for create_notification_subscription - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_notification_subscription_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the NotificationsApiService server but before - it is returned to user code. + it is returned to user code. This `post_create_notification_subscription` interceptor runs + before the `post_create_notification_subscription_with_metadata` interceptor. """ return response + def post_create_notification_subscription_with_metadata( + self, + response: notificationsapi.NotificationSubscription, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + notificationsapi.NotificationSubscription, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for create_notification_subscription + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the NotificationsApiService server but before it is returned to user code. + + We recommend only using this `post_create_notification_subscription_with_metadata` + interceptor in new development instead of the `post_create_notification_subscription` interceptor. + When both interceptors are used, this `post_create_notification_subscription_with_metadata` interceptor runs after the + `post_create_notification_subscription` interceptor. The (possibly modified) response returned by + `post_create_notification_subscription` will be passed to + `post_create_notification_subscription_with_metadata`. + """ + return response, metadata + def pre_delete_notification_subscription( self, request: notificationsapi.DeleteNotificationSubscriptionRequest, @@ -172,12 +198,38 @@ def post_get_notification_subscription( ) -> notificationsapi.NotificationSubscription: """Post-rpc interceptor for get_notification_subscription - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_notification_subscription_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the NotificationsApiService server but before - it is returned to user code. + it is returned to user code. This `post_get_notification_subscription` interceptor runs + before the `post_get_notification_subscription_with_metadata` interceptor. """ return response + def post_get_notification_subscription_with_metadata( + self, + response: notificationsapi.NotificationSubscription, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + notificationsapi.NotificationSubscription, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_notification_subscription + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the NotificationsApiService server but before it is returned to user code. + + We recommend only using this `post_get_notification_subscription_with_metadata` + interceptor in new development instead of the `post_get_notification_subscription` interceptor. + When both interceptors are used, this `post_get_notification_subscription_with_metadata` interceptor runs after the + `post_get_notification_subscription` interceptor. The (possibly modified) response returned by + `post_get_notification_subscription` will be passed to + `post_get_notification_subscription_with_metadata`. + """ + return response, metadata + def pre_list_notification_subscriptions( self, request: notificationsapi.ListNotificationSubscriptionsRequest, @@ -198,12 +250,38 @@ def post_list_notification_subscriptions( ) -> notificationsapi.ListNotificationSubscriptionsResponse: """Post-rpc interceptor for list_notification_subscriptions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_notification_subscriptions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the NotificationsApiService server but before - it is returned to user code. + it is returned to user code. This `post_list_notification_subscriptions` interceptor runs + before the `post_list_notification_subscriptions_with_metadata` interceptor. """ return response + def post_list_notification_subscriptions_with_metadata( + self, + response: notificationsapi.ListNotificationSubscriptionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + notificationsapi.ListNotificationSubscriptionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_notification_subscriptions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the NotificationsApiService server but before it is returned to user code. + + We recommend only using this `post_list_notification_subscriptions_with_metadata` + interceptor in new development instead of the `post_list_notification_subscriptions` interceptor. + When both interceptors are used, this `post_list_notification_subscriptions_with_metadata` interceptor runs after the + `post_list_notification_subscriptions` interceptor. The (possibly modified) response returned by + `post_list_notification_subscriptions` will be passed to + `post_list_notification_subscriptions_with_metadata`. + """ + return response, metadata + def pre_update_notification_subscription( self, request: notificationsapi.UpdateNotificationSubscriptionRequest, @@ -224,12 +302,38 @@ def post_update_notification_subscription( ) -> notificationsapi.NotificationSubscription: """Post-rpc interceptor for update_notification_subscription - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_notification_subscription_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the NotificationsApiService server but before - it is returned to user code. + it is returned to user code. This `post_update_notification_subscription` interceptor runs + before the `post_update_notification_subscription_with_metadata` interceptor. """ return response + def post_update_notification_subscription_with_metadata( + self, + response: notificationsapi.NotificationSubscription, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + notificationsapi.NotificationSubscription, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_notification_subscription + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the NotificationsApiService server but before it is returned to user code. + + We recommend only using this `post_update_notification_subscription_with_metadata` + interceptor in new development instead of the `post_update_notification_subscription` interceptor. + When both interceptors are used, this `post_update_notification_subscription_with_metadata` interceptor runs after the + `post_update_notification_subscription` interceptor. The (possibly modified) response returned by + `post_update_notification_subscription` will be passed to + `post_update_notification_subscription_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class NotificationsApiServiceRestStub: @@ -450,6 +554,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_notification_subscription(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_create_notification_subscription_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -715,6 +826,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_notification_subscription(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_notification_subscription_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -866,6 +984,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_notification_subscriptions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_notification_subscriptions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1026,6 +1151,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_notification_subscription(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_notification_subscription_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-notifications/noxfile.py b/packages/google-shopping-merchant-notifications/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-notifications/noxfile.py +++ b/packages/google-shopping-merchant-notifications/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json b/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json index fc4072bdf3ba..b27b3eb2144a 100644 --- a/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json +++ b/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-notifications", - "version": "0.1.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-notifications/tests/unit/gapic/merchant_notifications_v1beta/test_notifications_api_service.py b/packages/google-shopping-merchant-notifications/tests/unit/gapic/merchant_notifications_v1beta/test_notifications_api_service.py index 4c80bffc3327..d7a8c6fd043f 100644 --- a/packages/google-shopping-merchant-notifications/tests/unit/gapic/merchant_notifications_v1beta/test_notifications_api_service.py +++ b/packages/google-shopping-merchant-notifications/tests/unit/gapic/merchant_notifications_v1beta/test_notifications_api_service.py @@ -61,6 +61,13 @@ ) from google.shopping.merchant_notifications_v1beta.types import notificationsapi +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -336,6 +343,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = NotificationsApiServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = NotificationsApiServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4627,11 +4677,15 @@ def test_get_notification_subscription_rest_interceptors(null_interceptor): transports.NotificationsApiServiceRestInterceptor, "post_get_notification_subscription", ) as post, mock.patch.object( + transports.NotificationsApiServiceRestInterceptor, + "post_get_notification_subscription_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.NotificationsApiServiceRestInterceptor, "pre_get_notification_subscription", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = notificationsapi.GetNotificationSubscriptionRequest.pb( notificationsapi.GetNotificationSubscriptionRequest() ) @@ -4657,6 +4711,10 @@ def test_get_notification_subscription_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = notificationsapi.NotificationSubscription() + post_with_metadata.return_value = ( + notificationsapi.NotificationSubscription(), + metadata, + ) client.get_notification_subscription( request, @@ -4668,6 +4726,7 @@ def test_get_notification_subscription_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_notification_subscription_rest_bad_request( @@ -4841,11 +4900,15 @@ def test_create_notification_subscription_rest_interceptors(null_interceptor): transports.NotificationsApiServiceRestInterceptor, "post_create_notification_subscription", ) as post, mock.patch.object( + transports.NotificationsApiServiceRestInterceptor, + "post_create_notification_subscription_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.NotificationsApiServiceRestInterceptor, "pre_create_notification_subscription", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = notificationsapi.CreateNotificationSubscriptionRequest.pb( notificationsapi.CreateNotificationSubscriptionRequest() ) @@ -4871,6 +4934,10 @@ def test_create_notification_subscription_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = notificationsapi.NotificationSubscription() + post_with_metadata.return_value = ( + notificationsapi.NotificationSubscription(), + metadata, + ) client.create_notification_subscription( request, @@ -4882,6 +4949,7 @@ def test_create_notification_subscription_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_notification_subscription_rest_bad_request( @@ -5063,11 +5131,15 @@ def test_update_notification_subscription_rest_interceptors(null_interceptor): transports.NotificationsApiServiceRestInterceptor, "post_update_notification_subscription", ) as post, mock.patch.object( + transports.NotificationsApiServiceRestInterceptor, + "post_update_notification_subscription_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.NotificationsApiServiceRestInterceptor, "pre_update_notification_subscription", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = notificationsapi.UpdateNotificationSubscriptionRequest.pb( notificationsapi.UpdateNotificationSubscriptionRequest() ) @@ -5093,6 +5165,10 @@ def test_update_notification_subscription_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = notificationsapi.NotificationSubscription() + post_with_metadata.return_value = ( + notificationsapi.NotificationSubscription(), + metadata, + ) client.update_notification_subscription( request, @@ -5104,6 +5180,7 @@ def test_update_notification_subscription_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_notification_subscription_rest_bad_request( @@ -5301,11 +5378,15 @@ def test_list_notification_subscriptions_rest_interceptors(null_interceptor): transports.NotificationsApiServiceRestInterceptor, "post_list_notification_subscriptions", ) as post, mock.patch.object( + transports.NotificationsApiServiceRestInterceptor, + "post_list_notification_subscriptions_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.NotificationsApiServiceRestInterceptor, "pre_list_notification_subscriptions", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = notificationsapi.ListNotificationSubscriptionsRequest.pb( notificationsapi.ListNotificationSubscriptionsRequest() ) @@ -5331,6 +5412,10 @@ def test_list_notification_subscriptions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = notificationsapi.ListNotificationSubscriptionsResponse() + post_with_metadata.return_value = ( + notificationsapi.ListNotificationSubscriptionsResponse(), + metadata, + ) client.list_notification_subscriptions( request, @@ -5342,6 +5427,7 @@ def test_list_notification_subscriptions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-products/README.rst b/packages/google-shopping-merchant-products/README.rst index f8455a2d9403..de0805cae9a7 100644 --- a/packages/google-shopping-merchant-products/README.rst +++ b/packages/google-shopping-merchant-products/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py index 364164ddb134..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py index 364164ddb134..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/client.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/client.py index 86a77b8d40d5..80166eb85770 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/client.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -504,6 +506,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/transports/rest.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/transports/rest.py index 983e5ffa9fbc..49f111346fc3 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/transports/rest.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/product_inputs_service/transports/rest.py @@ -120,12 +120,35 @@ def post_insert_product_input( ) -> productinputs.ProductInput: """Post-rpc interceptor for insert_product_input - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_product_input_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductInputsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_product_input` interceptor runs + before the `post_insert_product_input_with_metadata` interceptor. """ return response + def post_insert_product_input_with_metadata( + self, + response: productinputs.ProductInput, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[productinputs.ProductInput, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_product_input + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductInputsService server but before it is returned to user code. + + We recommend only using this `post_insert_product_input_with_metadata` + interceptor in new development instead of the `post_insert_product_input` interceptor. + When both interceptors are used, this `post_insert_product_input_with_metadata` interceptor runs after the + `post_insert_product_input` interceptor. The (possibly modified) response returned by + `post_insert_product_input` will be passed to + `post_insert_product_input_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ProductInputsServiceRestStub: @@ -481,6 +504,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_product_input(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_product_input_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/client.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/client.py index 3bfbf848b272..fcf3dbd664d1 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/client.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/transports/rest.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/transports/rest.py index 2b0e1087d62f..dec81a9f5d19 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/transports/rest.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/services/products_service/transports/rest.py @@ -105,12 +105,35 @@ def pre_get_product( def post_get_product(self, response: products.Product) -> products.Product: """Post-rpc interceptor for get_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductsService server but before - it is returned to user code. + it is returned to user code. This `post_get_product` interceptor runs + before the `post_get_product_with_metadata` interceptor. """ return response + def post_get_product_with_metadata( + self, + response: products.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[products.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductsService server but before it is returned to user code. + + We recommend only using this `post_get_product_with_metadata` + interceptor in new development instead of the `post_get_product` interceptor. + When both interceptors are used, this `post_get_product_with_metadata` interceptor runs after the + `post_get_product` interceptor. The (possibly modified) response returned by + `post_get_product` will be passed to + `post_get_product_with_metadata`. + """ + return response, metadata + def pre_list_products( self, request: products.ListProductsRequest, @@ -128,12 +151,35 @@ def post_list_products( ) -> products.ListProductsResponse: """Post-rpc interceptor for list_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductsService server but before - it is returned to user code. + it is returned to user code. This `post_list_products` interceptor runs + before the `post_list_products_with_metadata` interceptor. """ return response + def post_list_products_with_metadata( + self, + response: products.ListProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[products.ListProductsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductsService server but before it is returned to user code. + + We recommend only using this `post_list_products_with_metadata` + interceptor in new development instead of the `post_list_products` interceptor. + When both interceptors are used, this `post_list_products_with_metadata` interceptor runs after the + `post_list_products` interceptor. The (possibly modified) response returned by + `post_list_products` will be passed to + `post_list_products_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ProductsServiceRestStub: @@ -357,6 +403,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -500,6 +550,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-products/noxfile.py b/packages/google-shopping-merchant-products/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-products/noxfile.py +++ b/packages/google-shopping-merchant-products/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json b/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json index 3f6381c5e11e..c50174f47a66 100644 --- a/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json +++ b/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-products", - "version": "0.2.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_product_inputs_service.py b/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_product_inputs_service.py index 5db6b4a1099f..afa48fecbb82 100644 --- a/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_product_inputs_service.py +++ b/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_product_inputs_service.py @@ -65,6 +65,13 @@ products_common, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductInputsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductInputsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2683,10 +2733,14 @@ def test_insert_product_input_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductInputsServiceRestInterceptor, "post_insert_product_input" ) as post, mock.patch.object( + transports.ProductInputsServiceRestInterceptor, + "post_insert_product_input_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductInputsServiceRestInterceptor, "pre_insert_product_input" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = productinputs.InsertProductInputRequest.pb( productinputs.InsertProductInputRequest() ) @@ -2710,6 +2764,7 @@ def test_insert_product_input_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = productinputs.ProductInput() + post_with_metadata.return_value = productinputs.ProductInput(), metadata client.insert_product_input( request, @@ -2721,6 +2776,7 @@ def test_insert_product_input_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_product_input_rest_bad_request( diff --git a/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_products_service.py b/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_products_service.py index 42d2656ad559..06a419c562e2 100644 --- a/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_products_service.py +++ b/packages/google-shopping-merchant-products/tests/unit/gapic/merchant_products_v1beta/test_products_service.py @@ -61,6 +61,13 @@ ) from google.shopping.merchant_products_v1beta.types import products, products_common +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2694,10 +2744,13 @@ def test_get_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductsServiceRestInterceptor, "post_get_product" ) as post, mock.patch.object( + transports.ProductsServiceRestInterceptor, "post_get_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductsServiceRestInterceptor, "pre_get_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = products.GetProductRequest.pb(products.GetProductRequest()) transcode.return_value = { "method": "post", @@ -2719,6 +2772,7 @@ def test_get_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = products.Product() + post_with_metadata.return_value = products.Product(), metadata client.get_product( request, @@ -2730,6 +2784,7 @@ def test_get_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_products_rest_bad_request(request_type=products.ListProductsRequest): @@ -2812,10 +2867,13 @@ def test_list_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductsServiceRestInterceptor, "post_list_products" ) as post, mock.patch.object( + transports.ProductsServiceRestInterceptor, "post_list_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductsServiceRestInterceptor, "pre_list_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = products.ListProductsRequest.pb(products.ListProductsRequest()) transcode.return_value = { "method": "post", @@ -2839,6 +2897,7 @@ def test_list_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = products.ListProductsResponse() + post_with_metadata.return_value = products.ListProductsResponse(), metadata client.list_products( request, @@ -2850,6 +2909,7 @@ def test_list_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-promotions/README.rst b/packages/google-shopping-merchant-promotions/README.rst index 1674328fa8ac..3218e86cd339 100644 --- a/packages/google-shopping-merchant-promotions/README.rst +++ b/packages/google-shopping-merchant-promotions/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/client.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/client.py index c589b0e7f7a0..450ea3a512ec 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/client.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -486,6 +488,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/transports/rest.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/transports/rest.py index 1cea05241158..824eed9be5b5 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/transports/rest.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/services/promotions_service/transports/rest.py @@ -115,12 +115,35 @@ def post_get_promotion( ) -> promotions.Promotion: """Post-rpc interceptor for get_promotion - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_promotion_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PromotionsService server but before - it is returned to user code. + it is returned to user code. This `post_get_promotion` interceptor runs + before the `post_get_promotion_with_metadata` interceptor. """ return response + def post_get_promotion_with_metadata( + self, + response: promotions.Promotion, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[promotions.Promotion, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_promotion + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PromotionsService server but before it is returned to user code. + + We recommend only using this `post_get_promotion_with_metadata` + interceptor in new development instead of the `post_get_promotion` interceptor. + When both interceptors are used, this `post_get_promotion_with_metadata` interceptor runs after the + `post_get_promotion` interceptor. The (possibly modified) response returned by + `post_get_promotion` will be passed to + `post_get_promotion_with_metadata`. + """ + return response, metadata + def pre_insert_promotion( self, request: promotions.InsertPromotionRequest, @@ -140,12 +163,35 @@ def post_insert_promotion( ) -> promotions.Promotion: """Post-rpc interceptor for insert_promotion - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_promotion_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PromotionsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_promotion` interceptor runs + before the `post_insert_promotion_with_metadata` interceptor. """ return response + def post_insert_promotion_with_metadata( + self, + response: promotions.Promotion, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[promotions.Promotion, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_promotion + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PromotionsService server but before it is returned to user code. + + We recommend only using this `post_insert_promotion_with_metadata` + interceptor in new development instead of the `post_insert_promotion` interceptor. + When both interceptors are used, this `post_insert_promotion_with_metadata` interceptor runs after the + `post_insert_promotion` interceptor. The (possibly modified) response returned by + `post_insert_promotion` will be passed to + `post_insert_promotion_with_metadata`. + """ + return response, metadata + def pre_list_promotions( self, request: promotions.ListPromotionsRequest, @@ -165,12 +211,37 @@ def post_list_promotions( ) -> promotions.ListPromotionsResponse: """Post-rpc interceptor for list_promotions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_promotions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PromotionsService server but before - it is returned to user code. + it is returned to user code. This `post_list_promotions` interceptor runs + before the `post_list_promotions_with_metadata` interceptor. """ return response + def post_list_promotions_with_metadata( + self, + response: promotions.ListPromotionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + promotions.ListPromotionsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_promotions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PromotionsService server but before it is returned to user code. + + We recommend only using this `post_list_promotions_with_metadata` + interceptor in new development instead of the `post_list_promotions` interceptor. + When both interceptors are used, this `post_list_promotions_with_metadata` interceptor runs after the + `post_list_promotions` interceptor. The (possibly modified) response returned by + `post_list_promotions` will be passed to + `post_list_promotions_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PromotionsServiceRestStub: @@ -389,6 +460,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_promotion(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_promotion_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -552,6 +627,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_promotion(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_promotion_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -693,6 +772,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_promotions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_promotions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-promotions/noxfile.py b/packages/google-shopping-merchant-promotions/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-promotions/noxfile.py +++ b/packages/google-shopping-merchant-promotions/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json b/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json index 7c0f6a67a96f..35c4091b4ca2 100644 --- a/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json +++ b/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-promotions", - "version": "0.1.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-promotions/tests/unit/gapic/merchant_promotions_v1beta/test_promotions_service.py b/packages/google-shopping-merchant-promotions/tests/unit/gapic/merchant_promotions_v1beta/test_promotions_service.py index f103f5757a16..5f220a42ee8c 100644 --- a/packages/google-shopping-merchant-promotions/tests/unit/gapic/merchant_promotions_v1beta/test_promotions_service.py +++ b/packages/google-shopping-merchant-promotions/tests/unit/gapic/merchant_promotions_v1beta/test_promotions_service.py @@ -66,6 +66,13 @@ promotions_common, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -333,6 +340,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PromotionsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PromotionsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3184,10 +3234,14 @@ def test_insert_promotion_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PromotionsServiceRestInterceptor, "post_insert_promotion" ) as post, mock.patch.object( + transports.PromotionsServiceRestInterceptor, + "post_insert_promotion_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PromotionsServiceRestInterceptor, "pre_insert_promotion" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = promotions.InsertPromotionRequest.pb( promotions.InsertPromotionRequest() ) @@ -3211,6 +3265,7 @@ def test_insert_promotion_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = promotions.Promotion() + post_with_metadata.return_value = promotions.Promotion(), metadata client.insert_promotion( request, @@ -3222,6 +3277,7 @@ def test_insert_promotion_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_promotion_rest_bad_request(request_type=promotions.GetPromotionRequest): @@ -3316,10 +3372,13 @@ def test_get_promotion_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PromotionsServiceRestInterceptor, "post_get_promotion" ) as post, mock.patch.object( + transports.PromotionsServiceRestInterceptor, "post_get_promotion_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PromotionsServiceRestInterceptor, "pre_get_promotion" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = promotions.GetPromotionRequest.pb(promotions.GetPromotionRequest()) transcode.return_value = { "method": "post", @@ -3341,6 +3400,7 @@ def test_get_promotion_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = promotions.Promotion() + post_with_metadata.return_value = promotions.Promotion(), metadata client.get_promotion( request, @@ -3352,6 +3412,7 @@ def test_get_promotion_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_promotions_rest_bad_request( @@ -3436,10 +3497,14 @@ def test_list_promotions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PromotionsServiceRestInterceptor, "post_list_promotions" ) as post, mock.patch.object( + transports.PromotionsServiceRestInterceptor, + "post_list_promotions_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PromotionsServiceRestInterceptor, "pre_list_promotions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = promotions.ListPromotionsRequest.pb( promotions.ListPromotionsRequest() ) @@ -3465,6 +3530,7 @@ def test_list_promotions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = promotions.ListPromotionsResponse() + post_with_metadata.return_value = promotions.ListPromotionsResponse(), metadata client.list_promotions( request, @@ -3476,6 +3542,7 @@ def test_list_promotions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-quota/README.rst b/packages/google-shopping-merchant-quota/README.rst index 5c9779cac8b3..9a6ad099f69e 100644 --- a/packages/google-shopping-merchant-quota/README.rst +++ b/packages/google-shopping-merchant-quota/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Shopping Merchant Quota.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Shopping Merchant Quota.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/client.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/client.py index ef3f0a2b9e34..9448142058bb 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/client.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -479,6 +481,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/transports/rest.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/transports/rest.py index 7ed3514e74c5..0c6aa8a1d5f6 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/transports/rest.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/services/quota_service/transports/rest.py @@ -99,12 +99,35 @@ def post_list_quota_groups( ) -> quota.ListQuotaGroupsResponse: """Post-rpc interceptor for list_quota_groups - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_quota_groups_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the QuotaService server but before - it is returned to user code. + it is returned to user code. This `post_list_quota_groups` interceptor runs + before the `post_list_quota_groups_with_metadata` interceptor. """ return response + def post_list_quota_groups_with_metadata( + self, + response: quota.ListQuotaGroupsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[quota.ListQuotaGroupsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_quota_groups + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the QuotaService server but before it is returned to user code. + + We recommend only using this `post_list_quota_groups_with_metadata` + interceptor in new development instead of the `post_list_quota_groups` interceptor. + When both interceptors are used, this `post_list_quota_groups_with_metadata` interceptor runs after the + `post_list_quota_groups` interceptor. The (possibly modified) response returned by + `post_list_quota_groups` will be passed to + `post_list_quota_groups_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class QuotaServiceRestStub: @@ -315,6 +338,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_quota_groups(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_quota_groups_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-quota/noxfile.py b/packages/google-shopping-merchant-quota/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-quota/noxfile.py +++ b/packages/google-shopping-merchant-quota/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json b/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json index b722ee9695ae..48037ddf7f53 100644 --- a/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json +++ b/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-quota", - "version": "0.1.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-quota/tests/unit/gapic/merchant_quota_v1beta/test_quota_service.py b/packages/google-shopping-merchant-quota/tests/unit/gapic/merchant_quota_v1beta/test_quota_service.py index 134ab619ae82..5632ffbf0d33 100644 --- a/packages/google-shopping-merchant-quota/tests/unit/gapic/merchant_quota_v1beta/test_quota_service.py +++ b/packages/google-shopping-merchant-quota/tests/unit/gapic/merchant_quota_v1beta/test_quota_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_quota_v1beta.types import quota +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -303,6 +310,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = QuotaServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = QuotaServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2094,10 +2144,13 @@ def test_list_quota_groups_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.QuotaServiceRestInterceptor, "post_list_quota_groups" ) as post, mock.patch.object( + transports.QuotaServiceRestInterceptor, "post_list_quota_groups_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.QuotaServiceRestInterceptor, "pre_list_quota_groups" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = quota.ListQuotaGroupsRequest.pb(quota.ListQuotaGroupsRequest()) transcode.return_value = { "method": "post", @@ -2121,6 +2174,7 @@ def test_list_quota_groups_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = quota.ListQuotaGroupsResponse() + post_with_metadata.return_value = quota.ListQuotaGroupsResponse(), metadata client.list_quota_groups( request, @@ -2132,6 +2186,7 @@ def test_list_quota_groups_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-reports/README.rst b/packages/google-shopping-merchant-reports/README.rst index 3b610c4a60f0..ec28e3200f7a 100644 --- a/packages/google-shopping-merchant-reports/README.rst +++ b/packages/google-shopping-merchant-reports/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant Reports API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant Reports API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/client.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/client.py index a80610a97821..431c9ad0dc48 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/client.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -463,6 +465,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/transports/rest.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/transports/rest.py index 8d9fb0e16582..a04e6d2a5690 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/transports/rest.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/services/report_service/transports/rest.py @@ -97,12 +97,35 @@ def pre_search( def post_search(self, response: reports.SearchResponse) -> reports.SearchResponse: """Post-rpc interceptor for search - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ReportService server but before - it is returned to user code. + it is returned to user code. This `post_search` interceptor runs + before the `post_search_with_metadata` interceptor. """ return response + def post_search_with_metadata( + self, + response: reports.SearchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[reports.SearchResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for search + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ReportService server but before it is returned to user code. + + We recommend only using this `post_search_with_metadata` + interceptor in new development instead of the `post_search` interceptor. + When both interceptors are used, this `post_search_with_metadata` interceptor runs after the + `post_search` interceptor. The (possibly modified) response returned by + `post_search` will be passed to + `post_search_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ReportServiceRestStub: @@ -319,6 +342,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-reports/noxfile.py b/packages/google-shopping-merchant-reports/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-reports/noxfile.py +++ b/packages/google-shopping-merchant-reports/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json b/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json index e0a7efc1923e..145fa5b7eb46 100644 --- a/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json +++ b/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-reports", - "version": "0.1.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-reports/tests/unit/gapic/merchant_reports_v1beta/test_report_service.py b/packages/google-shopping-merchant-reports/tests/unit/gapic/merchant_reports_v1beta/test_report_service.py index 64cffda0a359..f2e5f60e3986 100644 --- a/packages/google-shopping-merchant-reports/tests/unit/gapic/merchant_reports_v1beta/test_report_service.py +++ b/packages/google-shopping-merchant-reports/tests/unit/gapic/merchant_reports_v1beta/test_report_service.py @@ -60,6 +60,13 @@ ) from google.shopping.merchant_reports_v1beta.types import reports +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -314,6 +321,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ReportServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ReportServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2078,10 +2128,13 @@ def test_search_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ReportServiceRestInterceptor, "post_search" ) as post, mock.patch.object( + transports.ReportServiceRestInterceptor, "post_search_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ReportServiceRestInterceptor, "pre_search" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = reports.SearchRequest.pb(reports.SearchRequest()) transcode.return_value = { "method": "post", @@ -2103,6 +2156,7 @@ def test_search_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = reports.SearchResponse() + post_with_metadata.return_value = reports.SearchResponse(), metadata client.search( request, @@ -2114,6 +2168,7 @@ def test_search_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-shopping-merchant-reviews/README.rst b/packages/google-shopping-merchant-reviews/README.rst index 194d325703b9..f5dc29defb34 100644 --- a/packages/google-shopping-merchant-reviews/README.rst +++ b/packages/google-shopping-merchant-reviews/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Merchant Reviews API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Merchant Reviews API.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py index 33d37a7b677b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py index 33d37a7b677b..558c8aab67c5 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/client.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/client.py index 717cdc1ccf99..694ebc0631d7 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/client.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -488,6 +490,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/transports/rest.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/transports/rest.py index 2563acd573b4..a12888c50a6e 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/transports/rest.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/merchant_reviews_service/transports/rest.py @@ -138,12 +138,35 @@ def post_get_merchant_review( ) -> merchantreviews.MerchantReview: """Post-rpc interceptor for get_merchant_review - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_merchant_review_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MerchantReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_get_merchant_review` interceptor runs + before the `post_get_merchant_review_with_metadata` interceptor. """ return response + def post_get_merchant_review_with_metadata( + self, + response: merchantreviews.MerchantReview, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[merchantreviews.MerchantReview, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_merchant_review + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MerchantReviewsService server but before it is returned to user code. + + We recommend only using this `post_get_merchant_review_with_metadata` + interceptor in new development instead of the `post_get_merchant_review` interceptor. + When both interceptors are used, this `post_get_merchant_review_with_metadata` interceptor runs after the + `post_get_merchant_review` interceptor. The (possibly modified) response returned by + `post_get_merchant_review` will be passed to + `post_get_merchant_review_with_metadata`. + """ + return response, metadata + def pre_insert_merchant_review( self, request: merchantreviews.InsertMerchantReviewRequest, @@ -164,12 +187,35 @@ def post_insert_merchant_review( ) -> merchantreviews.MerchantReview: """Post-rpc interceptor for insert_merchant_review - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_merchant_review_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MerchantReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_merchant_review` interceptor runs + before the `post_insert_merchant_review_with_metadata` interceptor. """ return response + def post_insert_merchant_review_with_metadata( + self, + response: merchantreviews.MerchantReview, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[merchantreviews.MerchantReview, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_merchant_review + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MerchantReviewsService server but before it is returned to user code. + + We recommend only using this `post_insert_merchant_review_with_metadata` + interceptor in new development instead of the `post_insert_merchant_review` interceptor. + When both interceptors are used, this `post_insert_merchant_review_with_metadata` interceptor runs after the + `post_insert_merchant_review` interceptor. The (possibly modified) response returned by + `post_insert_merchant_review` will be passed to + `post_insert_merchant_review_with_metadata`. + """ + return response, metadata + def pre_list_merchant_reviews( self, request: merchantreviews.ListMerchantReviewsRequest, @@ -190,12 +236,38 @@ def post_list_merchant_reviews( ) -> merchantreviews.ListMerchantReviewsResponse: """Post-rpc interceptor for list_merchant_reviews - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_merchant_reviews_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MerchantReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_list_merchant_reviews` interceptor runs + before the `post_list_merchant_reviews_with_metadata` interceptor. """ return response + def post_list_merchant_reviews_with_metadata( + self, + response: merchantreviews.ListMerchantReviewsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + merchantreviews.ListMerchantReviewsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_merchant_reviews + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MerchantReviewsService server but before it is returned to user code. + + We recommend only using this `post_list_merchant_reviews_with_metadata` + interceptor in new development instead of the `post_list_merchant_reviews` interceptor. + When both interceptors are used, this `post_list_merchant_reviews_with_metadata` interceptor runs after the + `post_list_merchant_reviews` interceptor. The (possibly modified) response returned by + `post_list_merchant_reviews` will be passed to + `post_list_merchant_reviews_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class MerchantReviewsServiceRestStub: @@ -519,6 +591,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_merchant_review(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_merchant_review_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -673,6 +749,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_merchant_review(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_merchant_review_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -818,6 +898,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_merchant_reviews(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_merchant_reviews_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/client.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/client.py index b79d1709b773..ff750b6d57f1 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/client.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/transports/rest.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/transports/rest.py index d4be47b80be6..6b5a0329b4c6 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/transports/rest.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/services/product_reviews_service/transports/rest.py @@ -137,12 +137,35 @@ def post_get_product_review( ) -> productreviews.ProductReview: """Post-rpc interceptor for get_product_review - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_product_review_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_get_product_review` interceptor runs + before the `post_get_product_review_with_metadata` interceptor. """ return response + def post_get_product_review_with_metadata( + self, + response: productreviews.ProductReview, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[productreviews.ProductReview, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_product_review + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductReviewsService server but before it is returned to user code. + + We recommend only using this `post_get_product_review_with_metadata` + interceptor in new development instead of the `post_get_product_review` interceptor. + When both interceptors are used, this `post_get_product_review_with_metadata` interceptor runs after the + `post_get_product_review` interceptor. The (possibly modified) response returned by + `post_get_product_review` will be passed to + `post_get_product_review_with_metadata`. + """ + return response, metadata + def pre_insert_product_review( self, request: productreviews.InsertProductReviewRequest, @@ -163,12 +186,35 @@ def post_insert_product_review( ) -> productreviews.ProductReview: """Post-rpc interceptor for insert_product_review - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_insert_product_review_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_insert_product_review` interceptor runs + before the `post_insert_product_review_with_metadata` interceptor. """ return response + def post_insert_product_review_with_metadata( + self, + response: productreviews.ProductReview, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[productreviews.ProductReview, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for insert_product_review + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductReviewsService server but before it is returned to user code. + + We recommend only using this `post_insert_product_review_with_metadata` + interceptor in new development instead of the `post_insert_product_review` interceptor. + When both interceptors are used, this `post_insert_product_review_with_metadata` interceptor runs after the + `post_insert_product_review` interceptor. The (possibly modified) response returned by + `post_insert_product_review` will be passed to + `post_insert_product_review_with_metadata`. + """ + return response, metadata + def pre_list_product_reviews( self, request: productreviews.ListProductReviewsRequest, @@ -189,12 +235,38 @@ def post_list_product_reviews( ) -> productreviews.ListProductReviewsResponse: """Post-rpc interceptor for list_product_reviews - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_product_reviews_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductReviewsService server but before - it is returned to user code. + it is returned to user code. This `post_list_product_reviews` interceptor runs + before the `post_list_product_reviews_with_metadata` interceptor. """ return response + def post_list_product_reviews_with_metadata( + self, + response: productreviews.ListProductReviewsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + productreviews.ListProductReviewsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_product_reviews + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductReviewsService server but before it is returned to user code. + + We recommend only using this `post_list_product_reviews_with_metadata` + interceptor in new development instead of the `post_list_product_reviews` interceptor. + When both interceptors are used, this `post_list_product_reviews_with_metadata` interceptor runs after the + `post_list_product_reviews` interceptor. The (possibly modified) response returned by + `post_list_product_reviews` will be passed to + `post_list_product_reviews_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ProductReviewsServiceRestStub: @@ -519,6 +591,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_product_review(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_product_review_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -673,6 +749,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_insert_product_review(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_insert_product_review_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -821,6 +901,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_product_reviews(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_product_reviews_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-shopping-merchant-reviews/noxfile.py b/packages/google-shopping-merchant-reviews/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-merchant-reviews/noxfile.py +++ b/packages/google-shopping-merchant-reviews/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_merchant_reviews_service.py b/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_merchant_reviews_service.py index d93647e8c193..8aa415c2ca2a 100644 --- a/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_merchant_reviews_service.py +++ b/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_merchant_reviews_service.py @@ -65,6 +65,13 @@ merchantreviews_common, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -340,6 +347,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = MerchantReviewsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = MerchantReviewsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3816,10 +3866,14 @@ def test_get_merchant_review_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "post_get_merchant_review" ) as post, mock.patch.object( + transports.MerchantReviewsServiceRestInterceptor, + "post_get_merchant_review_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "pre_get_merchant_review" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = merchantreviews.GetMerchantReviewRequest.pb( merchantreviews.GetMerchantReviewRequest() ) @@ -3845,6 +3899,7 @@ def test_get_merchant_review_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = merchantreviews.MerchantReview() + post_with_metadata.return_value = merchantreviews.MerchantReview(), metadata client.get_merchant_review( request, @@ -3856,6 +3911,7 @@ def test_get_merchant_review_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_merchant_reviews_rest_bad_request( @@ -3940,10 +3996,14 @@ def test_list_merchant_reviews_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "post_list_merchant_reviews" ) as post, mock.patch.object( + transports.MerchantReviewsServiceRestInterceptor, + "post_list_merchant_reviews_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "pre_list_merchant_reviews" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = merchantreviews.ListMerchantReviewsRequest.pb( merchantreviews.ListMerchantReviewsRequest() ) @@ -3969,6 +4029,10 @@ def test_list_merchant_reviews_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = merchantreviews.ListMerchantReviewsResponse() + post_with_metadata.return_value = ( + merchantreviews.ListMerchantReviewsResponse(), + metadata, + ) client.list_merchant_reviews( request, @@ -3980,6 +4044,7 @@ def test_list_merchant_reviews_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_merchant_review_rest_bad_request( @@ -4180,10 +4245,14 @@ def test_insert_merchant_review_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "post_insert_merchant_review" ) as post, mock.patch.object( + transports.MerchantReviewsServiceRestInterceptor, + "post_insert_merchant_review_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MerchantReviewsServiceRestInterceptor, "pre_insert_merchant_review" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = merchantreviews.InsertMerchantReviewRequest.pb( merchantreviews.InsertMerchantReviewRequest() ) @@ -4209,6 +4278,7 @@ def test_insert_merchant_review_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = merchantreviews.MerchantReview() + post_with_metadata.return_value = merchantreviews.MerchantReview(), metadata client.insert_merchant_review( request, @@ -4220,6 +4290,7 @@ def test_insert_merchant_review_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_merchant_review_rest_bad_request( diff --git a/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_product_reviews_service.py b/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_product_reviews_service.py index ab13891c241b..e8cc664e5207 100644 --- a/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_product_reviews_service.py +++ b/packages/google-shopping-merchant-reviews/tests/unit/gapic/merchant_reviews_v1beta/test_product_reviews_service.py @@ -65,6 +65,13 @@ productreviews_common, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -340,6 +347,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductReviewsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductReviewsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3811,10 +3861,14 @@ def test_get_product_review_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "post_get_product_review" ) as post, mock.patch.object( + transports.ProductReviewsServiceRestInterceptor, + "post_get_product_review_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "pre_get_product_review" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = productreviews.GetProductReviewRequest.pb( productreviews.GetProductReviewRequest() ) @@ -3840,6 +3894,7 @@ def test_get_product_review_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = productreviews.ProductReview() + post_with_metadata.return_value = productreviews.ProductReview(), metadata client.get_product_review( request, @@ -3851,6 +3906,7 @@ def test_get_product_review_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_product_reviews_rest_bad_request( @@ -3935,10 +3991,14 @@ def test_list_product_reviews_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "post_list_product_reviews" ) as post, mock.patch.object( + transports.ProductReviewsServiceRestInterceptor, + "post_list_product_reviews_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "pre_list_product_reviews" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = productreviews.ListProductReviewsRequest.pb( productreviews.ListProductReviewsRequest() ) @@ -3964,6 +4024,10 @@ def test_list_product_reviews_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = productreviews.ListProductReviewsResponse() + post_with_metadata.return_value = ( + productreviews.ListProductReviewsResponse(), + metadata, + ) client.list_product_reviews( request, @@ -3975,6 +4039,7 @@ def test_list_product_reviews_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_insert_product_review_rest_bad_request( @@ -4189,10 +4254,14 @@ def test_insert_product_review_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "post_insert_product_review" ) as post, mock.patch.object( + transports.ProductReviewsServiceRestInterceptor, + "post_insert_product_review_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductReviewsServiceRestInterceptor, "pre_insert_product_review" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = productreviews.InsertProductReviewRequest.pb( productreviews.InsertProductReviewRequest() ) @@ -4218,6 +4287,7 @@ def test_insert_product_review_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = productreviews.ProductReview() + post_with_metadata.return_value = productreviews.ProductReview(), metadata client.insert_product_review( request, @@ -4229,6 +4299,7 @@ def test_insert_product_review_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_product_review_rest_bad_request( diff --git a/packages/google-shopping-type/README.rst b/packages/google-shopping-type/README.rst index fa8f2eadfe54..061ecbe8625d 100644 --- a/packages/google-shopping-type/README.rst +++ b/packages/google-shopping-type/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Shopping Type Protos.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Shopping Type Protos.: https://developers.google.com/merchant/api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-shopping-type/google/shopping/type/gapic_version.py b/packages/google-shopping-type/google/shopping/type/gapic_version.py index f8ea948a9c30..558c8aab67c5 100644 --- a/packages/google-shopping-type/google/shopping/type/gapic_version.py +++ b/packages/google-shopping-type/google/shopping/type/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.9" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-type/noxfile.py b/packages/google-shopping-type/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-shopping-type/noxfile.py +++ b/packages/google-shopping-type/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/grafeas/README.rst b/packages/grafeas/README.rst index 2a2eb6288f31..c8221ae59f67 100644 --- a/packages/grafeas/README.rst +++ b/packages/grafeas/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Grafeas.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Grafeas.: https://grafeas.io -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/grafeas/grafeas/grafeas/gapic_version.py b/packages/grafeas/grafeas/grafeas/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/grafeas/grafeas/grafeas/gapic_version.py +++ b/packages/grafeas/grafeas/grafeas/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/grafeas/grafeas/grafeas_v1/gapic_version.py b/packages/grafeas/grafeas/grafeas_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/grafeas/grafeas/grafeas_v1/gapic_version.py +++ b/packages/grafeas/grafeas/grafeas_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/grafeas/grafeas/grafeas_v1/services/grafeas/client.py b/packages/grafeas/grafeas/grafeas_v1/services/grafeas/client.py index 51567402e6b4..db8ca667efce 100644 --- a/packages/grafeas/grafeas/grafeas_v1/services/grafeas/client.py +++ b/packages/grafeas/grafeas/grafeas_v1/services/grafeas/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re diff --git a/packages/grafeas/grafeas/grafeas_v1/services/grafeas/transports/rest.py b/packages/grafeas/grafeas/grafeas_v1/services/grafeas/transports/rest.py index 96821ab0a7ee..8f652e84f17d 100644 --- a/packages/grafeas/grafeas/grafeas_v1/services/grafeas/transports/rest.py +++ b/packages/grafeas/grafeas/grafeas_v1/services/grafeas/transports/rest.py @@ -198,12 +198,37 @@ def post_batch_create_notes( ) -> grafeas.BatchCreateNotesResponse: """Post-rpc interceptor for batch_create_notes - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_create_notes_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_batch_create_notes` interceptor runs + before the `post_batch_create_notes_with_metadata` interceptor. """ return response + def post_batch_create_notes_with_metadata( + self, + response: grafeas.BatchCreateNotesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + grafeas.BatchCreateNotesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for batch_create_notes + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_batch_create_notes_with_metadata` + interceptor in new development instead of the `post_batch_create_notes` interceptor. + When both interceptors are used, this `post_batch_create_notes_with_metadata` interceptor runs after the + `post_batch_create_notes` interceptor. The (possibly modified) response returned by + `post_batch_create_notes` will be passed to + `post_batch_create_notes_with_metadata`. + """ + return response, metadata + def pre_batch_create_occurrences( self, request: grafeas.BatchCreateOccurrencesRequest, @@ -223,12 +248,37 @@ def post_batch_create_occurrences( ) -> grafeas.BatchCreateOccurrencesResponse: """Post-rpc interceptor for batch_create_occurrences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_create_occurrences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_batch_create_occurrences` interceptor runs + before the `post_batch_create_occurrences_with_metadata` interceptor. """ return response + def post_batch_create_occurrences_with_metadata( + self, + response: grafeas.BatchCreateOccurrencesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + grafeas.BatchCreateOccurrencesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for batch_create_occurrences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_batch_create_occurrences_with_metadata` + interceptor in new development instead of the `post_batch_create_occurrences` interceptor. + When both interceptors are used, this `post_batch_create_occurrences_with_metadata` interceptor runs after the + `post_batch_create_occurrences` interceptor. The (possibly modified) response returned by + `post_batch_create_occurrences` will be passed to + `post_batch_create_occurrences_with_metadata`. + """ + return response, metadata + def pre_create_note( self, request: grafeas.CreateNoteRequest, @@ -244,12 +294,33 @@ def pre_create_note( def post_create_note(self, response: grafeas.Note) -> grafeas.Note: """Post-rpc interceptor for create_note - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_note_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_create_note` interceptor runs + before the `post_create_note_with_metadata` interceptor. """ return response + def post_create_note_with_metadata( + self, response: grafeas.Note, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[grafeas.Note, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_note + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_create_note_with_metadata` + interceptor in new development instead of the `post_create_note` interceptor. + When both interceptors are used, this `post_create_note_with_metadata` interceptor runs after the + `post_create_note` interceptor. The (possibly modified) response returned by + `post_create_note` will be passed to + `post_create_note_with_metadata`. + """ + return response, metadata + def pre_create_occurrence( self, request: grafeas.CreateOccurrenceRequest, @@ -269,12 +340,35 @@ def post_create_occurrence( ) -> grafeas.Occurrence: """Post-rpc interceptor for create_occurrence - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_occurrence_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_create_occurrence` interceptor runs + before the `post_create_occurrence_with_metadata` interceptor. """ return response + def post_create_occurrence_with_metadata( + self, + response: grafeas.Occurrence, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[grafeas.Occurrence, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_occurrence + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_create_occurrence_with_metadata` + interceptor in new development instead of the `post_create_occurrence` interceptor. + When both interceptors are used, this `post_create_occurrence_with_metadata` interceptor runs after the + `post_create_occurrence` interceptor. The (possibly modified) response returned by + `post_create_occurrence` will be passed to + `post_create_occurrence_with_metadata`. + """ + return response, metadata + def pre_delete_note( self, request: grafeas.DeleteNoteRequest, @@ -316,12 +410,33 @@ def pre_get_note( def post_get_note(self, response: grafeas.Note) -> grafeas.Note: """Post-rpc interceptor for get_note - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_note_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_get_note` interceptor runs + before the `post_get_note_with_metadata` interceptor. """ return response + def post_get_note_with_metadata( + self, response: grafeas.Note, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[grafeas.Note, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_note + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_get_note_with_metadata` + interceptor in new development instead of the `post_get_note` interceptor. + When both interceptors are used, this `post_get_note_with_metadata` interceptor runs after the + `post_get_note` interceptor. The (possibly modified) response returned by + `post_get_note` will be passed to + `post_get_note_with_metadata`. + """ + return response, metadata + def pre_get_occurrence( self, request: grafeas.GetOccurrenceRequest, @@ -337,12 +452,35 @@ def pre_get_occurrence( def post_get_occurrence(self, response: grafeas.Occurrence) -> grafeas.Occurrence: """Post-rpc interceptor for get_occurrence - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_occurrence_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_get_occurrence` interceptor runs + before the `post_get_occurrence_with_metadata` interceptor. """ return response + def post_get_occurrence_with_metadata( + self, + response: grafeas.Occurrence, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[grafeas.Occurrence, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_occurrence + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_get_occurrence_with_metadata` + interceptor in new development instead of the `post_get_occurrence` interceptor. + When both interceptors are used, this `post_get_occurrence_with_metadata` interceptor runs after the + `post_get_occurrence` interceptor. The (possibly modified) response returned by + `post_get_occurrence` will be passed to + `post_get_occurrence_with_metadata`. + """ + return response, metadata + def pre_get_occurrence_note( self, request: grafeas.GetOccurrenceNoteRequest, @@ -360,12 +498,33 @@ def pre_get_occurrence_note( def post_get_occurrence_note(self, response: grafeas.Note) -> grafeas.Note: """Post-rpc interceptor for get_occurrence_note - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_occurrence_note_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_get_occurrence_note` interceptor runs + before the `post_get_occurrence_note_with_metadata` interceptor. """ return response + def post_get_occurrence_note_with_metadata( + self, response: grafeas.Note, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[grafeas.Note, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_occurrence_note + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_get_occurrence_note_with_metadata` + interceptor in new development instead of the `post_get_occurrence_note` interceptor. + When both interceptors are used, this `post_get_occurrence_note_with_metadata` interceptor runs after the + `post_get_occurrence_note` interceptor. The (possibly modified) response returned by + `post_get_occurrence_note` will be passed to + `post_get_occurrence_note_with_metadata`. + """ + return response, metadata + def pre_list_note_occurrences( self, request: grafeas.ListNoteOccurrencesRequest, @@ -385,12 +544,37 @@ def post_list_note_occurrences( ) -> grafeas.ListNoteOccurrencesResponse: """Post-rpc interceptor for list_note_occurrences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_note_occurrences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_list_note_occurrences` interceptor runs + before the `post_list_note_occurrences_with_metadata` interceptor. """ return response + def post_list_note_occurrences_with_metadata( + self, + response: grafeas.ListNoteOccurrencesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + grafeas.ListNoteOccurrencesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_note_occurrences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_list_note_occurrences_with_metadata` + interceptor in new development instead of the `post_list_note_occurrences` interceptor. + When both interceptors are used, this `post_list_note_occurrences_with_metadata` interceptor runs after the + `post_list_note_occurrences` interceptor. The (possibly modified) response returned by + `post_list_note_occurrences` will be passed to + `post_list_note_occurrences_with_metadata`. + """ + return response, metadata + def pre_list_notes( self, request: grafeas.ListNotesRequest, @@ -408,12 +592,35 @@ def post_list_notes( ) -> grafeas.ListNotesResponse: """Post-rpc interceptor for list_notes - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_notes_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_list_notes` interceptor runs + before the `post_list_notes_with_metadata` interceptor. """ return response + def post_list_notes_with_metadata( + self, + response: grafeas.ListNotesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[grafeas.ListNotesResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_notes + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_list_notes_with_metadata` + interceptor in new development instead of the `post_list_notes` interceptor. + When both interceptors are used, this `post_list_notes_with_metadata` interceptor runs after the + `post_list_notes` interceptor. The (possibly modified) response returned by + `post_list_notes` will be passed to + `post_list_notes_with_metadata`. + """ + return response, metadata + def pre_list_occurrences( self, request: grafeas.ListOccurrencesRequest, @@ -431,12 +638,37 @@ def post_list_occurrences( ) -> grafeas.ListOccurrencesResponse: """Post-rpc interceptor for list_occurrences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_occurrences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_list_occurrences` interceptor runs + before the `post_list_occurrences_with_metadata` interceptor. """ return response + def post_list_occurrences_with_metadata( + self, + response: grafeas.ListOccurrencesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + grafeas.ListOccurrencesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_occurrences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_list_occurrences_with_metadata` + interceptor in new development instead of the `post_list_occurrences` interceptor. + When both interceptors are used, this `post_list_occurrences_with_metadata` interceptor runs after the + `post_list_occurrences` interceptor. The (possibly modified) response returned by + `post_list_occurrences` will be passed to + `post_list_occurrences_with_metadata`. + """ + return response, metadata + def pre_update_note( self, request: grafeas.UpdateNoteRequest, @@ -452,12 +684,33 @@ def pre_update_note( def post_update_note(self, response: grafeas.Note) -> grafeas.Note: """Post-rpc interceptor for update_note - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_note_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_update_note` interceptor runs + before the `post_update_note_with_metadata` interceptor. """ return response + def post_update_note_with_metadata( + self, response: grafeas.Note, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[grafeas.Note, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_note + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_update_note_with_metadata` + interceptor in new development instead of the `post_update_note` interceptor. + When both interceptors are used, this `post_update_note_with_metadata` interceptor runs after the + `post_update_note` interceptor. The (possibly modified) response returned by + `post_update_note` will be passed to + `post_update_note_with_metadata`. + """ + return response, metadata + def pre_update_occurrence( self, request: grafeas.UpdateOccurrenceRequest, @@ -477,12 +730,35 @@ def post_update_occurrence( ) -> grafeas.Occurrence: """Post-rpc interceptor for update_occurrence - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_occurrence_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Grafeas server but before - it is returned to user code. + it is returned to user code. This `post_update_occurrence` interceptor runs + before the `post_update_occurrence_with_metadata` interceptor. """ return response + def post_update_occurrence_with_metadata( + self, + response: grafeas.Occurrence, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[grafeas.Occurrence, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_occurrence + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Grafeas server but before it is returned to user code. + + We recommend only using this `post_update_occurrence_with_metadata` + interceptor in new development instead of the `post_update_occurrence` interceptor. + When both interceptors are used, this `post_update_occurrence_with_metadata` interceptor runs after the + `post_update_occurrence` interceptor. The (possibly modified) response returned by + `post_update_occurrence` will be passed to + `post_update_occurrence_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class GrafeasRestStub: @@ -716,6 +992,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_create_notes(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_batch_create_notes_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -869,6 +1149,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_create_occurrences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_batch_create_occurrences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1019,6 +1303,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_note(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_note_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1175,6 +1463,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_occurrence(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_occurrence_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1535,6 +1827,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_note(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_note_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1679,6 +1975,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_occurrence(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_occurrence_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1826,6 +2126,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_occurrence_note(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_occurrence_note_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1971,6 +2275,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_note_occurrences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_note_occurrences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2113,6 +2421,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_notes(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_notes_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2259,6 +2571,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_occurrences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_occurrences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2407,6 +2723,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_note(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_note_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2563,6 +2883,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_occurrence(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_occurrence_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/grafeas/noxfile.py b/packages/grafeas/noxfile.py index 62a0480d833f..a732c758251a 100644 --- a/packages/grafeas/noxfile.py +++ b/packages/grafeas/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json b/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json index d1e44ca1a5a8..290215d3171d 100644 --- a/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json +++ b/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "grafeas", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/grafeas/tests/unit/gapic/grafeas_v1/test_grafeas.py b/packages/grafeas/tests/unit/gapic/grafeas_v1/test_grafeas.py index 4cb82f78f551..276bf7929a6a 100644 --- a/packages/grafeas/tests/unit/gapic/grafeas_v1/test_grafeas.py +++ b/packages/grafeas/tests/unit/gapic/grafeas_v1/test_grafeas.py @@ -87,6 +87,13 @@ vulnerability, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -9204,10 +9211,13 @@ def test_get_occurrence_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_get_occurrence" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_get_occurrence_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_get_occurrence" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.GetOccurrenceRequest.pb(grafeas.GetOccurrenceRequest()) transcode.return_value = { "method": "post", @@ -9229,6 +9239,7 @@ def test_get_occurrence_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Occurrence() + post_with_metadata.return_value = grafeas.Occurrence(), metadata client.get_occurrence( request, @@ -9240,6 +9251,7 @@ def test_get_occurrence_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_occurrences_rest_bad_request(request_type=grafeas.ListOccurrencesRequest): @@ -9320,10 +9332,13 @@ def test_list_occurrences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_list_occurrences" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_list_occurrences_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_list_occurrences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.ListOccurrencesRequest.pb(grafeas.ListOccurrencesRequest()) transcode.return_value = { "method": "post", @@ -9347,6 +9362,7 @@ def test_list_occurrences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.ListOccurrencesResponse() + post_with_metadata.return_value = grafeas.ListOccurrencesResponse(), metadata client.list_occurrences( request, @@ -9358,6 +9374,7 @@ def test_list_occurrences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_occurrence_rest_bad_request( @@ -9992,10 +10009,13 @@ def test_create_occurrence_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_create_occurrence" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_create_occurrence_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_create_occurrence" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.CreateOccurrenceRequest.pb( grafeas.CreateOccurrenceRequest() ) @@ -10019,6 +10039,7 @@ def test_create_occurrence_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Occurrence() + post_with_metadata.return_value = grafeas.Occurrence(), metadata client.create_occurrence( request, @@ -10030,6 +10051,7 @@ def test_create_occurrence_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_create_occurrences_rest_bad_request( @@ -10109,10 +10131,13 @@ def test_batch_create_occurrences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_batch_create_occurrences" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_batch_create_occurrences_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_batch_create_occurrences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.BatchCreateOccurrencesRequest.pb( grafeas.BatchCreateOccurrencesRequest() ) @@ -10138,6 +10163,10 @@ def test_batch_create_occurrences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.BatchCreateOccurrencesResponse() + post_with_metadata.return_value = ( + grafeas.BatchCreateOccurrencesResponse(), + metadata, + ) client.batch_create_occurrences( request, @@ -10149,6 +10178,7 @@ def test_batch_create_occurrences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_occurrence_rest_bad_request( @@ -10676,10 +10706,13 @@ def test_update_occurrence_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_update_occurrence" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_update_occurrence_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_update_occurrence" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.UpdateOccurrenceRequest.pb( grafeas.UpdateOccurrenceRequest() ) @@ -10703,6 +10736,7 @@ def test_update_occurrence_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Occurrence() + post_with_metadata.return_value = grafeas.Occurrence(), metadata client.update_occurrence( request, @@ -10714,6 +10748,7 @@ def test_update_occurrence_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_occurrence_note_rest_bad_request( @@ -10804,10 +10839,13 @@ def test_get_occurrence_note_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_get_occurrence_note" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_get_occurrence_note_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_get_occurrence_note" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.GetOccurrenceNoteRequest.pb( grafeas.GetOccurrenceNoteRequest() ) @@ -10831,6 +10869,7 @@ def test_get_occurrence_note_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Note() + post_with_metadata.return_value = grafeas.Note(), metadata client.get_occurrence_note( request, @@ -10842,6 +10881,7 @@ def test_get_occurrence_note_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_note_rest_bad_request(request_type=grafeas.GetNoteRequest): @@ -10930,10 +10970,13 @@ def test_get_note_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_get_note" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_get_note_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_get_note" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.GetNoteRequest.pb(grafeas.GetNoteRequest()) transcode.return_value = { "method": "post", @@ -10955,6 +10998,7 @@ def test_get_note_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Note() + post_with_metadata.return_value = grafeas.Note(), metadata client.get_note( request, @@ -10966,6 +11010,7 @@ def test_get_note_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_notes_rest_bad_request(request_type=grafeas.ListNotesRequest): @@ -11046,10 +11091,13 @@ def test_list_notes_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_list_notes" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_list_notes_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_list_notes" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.ListNotesRequest.pb(grafeas.ListNotesRequest()) transcode.return_value = { "method": "post", @@ -11071,6 +11119,7 @@ def test_list_notes_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.ListNotesResponse() + post_with_metadata.return_value = grafeas.ListNotesResponse(), metadata client.list_notes( request, @@ -11082,6 +11131,7 @@ def test_list_notes_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_note_rest_bad_request(request_type=grafeas.DeleteNoteRequest): @@ -11533,10 +11583,13 @@ def test_create_note_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_create_note" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_create_note_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_create_note" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.CreateNoteRequest.pb(grafeas.CreateNoteRequest()) transcode.return_value = { "method": "post", @@ -11558,6 +11611,7 @@ def test_create_note_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Note() + post_with_metadata.return_value = grafeas.Note(), metadata client.create_note( request, @@ -11569,6 +11623,7 @@ def test_create_note_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_create_notes_rest_bad_request( @@ -11648,10 +11703,13 @@ def test_batch_create_notes_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_batch_create_notes" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_batch_create_notes_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_batch_create_notes" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.BatchCreateNotesRequest.pb( grafeas.BatchCreateNotesRequest() ) @@ -11677,6 +11735,7 @@ def test_batch_create_notes_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.BatchCreateNotesResponse() + post_with_metadata.return_value = grafeas.BatchCreateNotesResponse(), metadata client.batch_create_notes( request, @@ -11688,6 +11747,7 @@ def test_batch_create_notes_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_note_rest_bad_request(request_type=grafeas.UpdateNoteRequest): @@ -12036,10 +12096,13 @@ def test_update_note_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_update_note" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_update_note_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_update_note" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.UpdateNoteRequest.pb(grafeas.UpdateNoteRequest()) transcode.return_value = { "method": "post", @@ -12061,6 +12124,7 @@ def test_update_note_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.Note() + post_with_metadata.return_value = grafeas.Note(), metadata client.update_note( request, @@ -12072,6 +12136,7 @@ def test_update_note_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_note_occurrences_rest_bad_request( @@ -12154,10 +12219,13 @@ def test_list_note_occurrences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.GrafeasRestInterceptor, "post_list_note_occurrences" ) as post, mock.patch.object( + transports.GrafeasRestInterceptor, "post_list_note_occurrences_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.GrafeasRestInterceptor, "pre_list_note_occurrences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = grafeas.ListNoteOccurrencesRequest.pb( grafeas.ListNoteOccurrencesRequest() ) @@ -12183,6 +12251,10 @@ def test_list_note_occurrences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = grafeas.ListNoteOccurrencesResponse() + post_with_metadata.return_value = ( + grafeas.ListNoteOccurrencesResponse(), + metadata, + ) client.list_note_occurrences( request, @@ -12194,6 +12266,7 @@ def test_list_note_occurrences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/scripts/client-post-processing/unique-grafeas-client.yaml b/scripts/client-post-processing/unique-grafeas-client.yaml index 26e2d17ed925..9965bc00cccd 100644 --- a/scripts/client-post-processing/unique-grafeas-client.yaml +++ b/scripts/client-post-processing/unique-grafeas-client.yaml @@ -581,6 +581,49 @@ replacements: assert str\(excinfo.value\) == "Universe Domain cannot be an empty string." + @pytest.mark.parametrize\( + "error_code,cred_info_json,show_cred_info", + \[ + \(401, CRED_INFO_JSON, True\), + \(403, CRED_INFO_JSON, True\), + \(404, CRED_INFO_JSON, True\), + \(500, CRED_INFO_JSON, False\), + \(401, None, False\), + \(403, None, False\), + \(404, None, False\), + \(500, None, False\), + \], + \) + def test__add_cred_info_for_auth_errors\(error_code, cred_info_json, show_cred_info\): + cred = mock.Mock\(\["get_cred_info"\]\) + cred.get_cred_info = mock.Mock\(return_value=cred_info_json\) + client = GrafeasClient\(credentials=cred\) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError\("message", details=\["foo"\]\) + error.code = error_code + + client._add_cred_info_for_auth_errors\(error\) + if show_cred_info: + assert error.details == \["foo", CRED_INFO_STRING\] + else: + assert error.details == \["foo"\] + + + @pytest.mark.parametrize\("error_code", \[401, 403, 404, 500\]\) + def test__add_cred_info_for_auth_errors_no_get_cred_info\(error_code\): + cred = mock.Mock\(\[\]\) + assert not hasattr\(cred, "get_cred_info"\) + client = GrafeasClient\(credentials=cred\) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError\("message", details=\[\]\) + error.code = error_code + + client._add_cred_info_for_auth_errors\(error\) + assert error.details == \[\] + + @pytest.mark.parametrize\( "client_class,transport_name", \[ @@ -1498,6 +1541,33 @@ replacements: \ # NOTE \(b\/349488459\): universe validation is disabled until further notice. \ return True \ + \ def _add_cred_info_for_auth_errors\( + \ self, error: core_exceptions.GoogleAPICallError + \ \) -> None: + \ """Adds credential info string to error details for 401/403/404 errors. + \ + \ Args: + \ error \(google.api_core.exceptions.GoogleAPICallError\): The error to add the cred info. + \ """ + \ if error.code not in \[ + \ HTTPStatus.UNAUTHORIZED, + \ HTTPStatus.FORBIDDEN, + \ HTTPStatus.NOT_FOUND, + \ \]: + \ return + \ + \ cred = self._transport._credentials + \ + \ # get_cred_info is only available in google-auth>=2.35.0 + \ if not hasattr\(cred, "get_cred_info"\): + \ return + \ + \ # ignore the type check since pypy test fails when get_cred_info + \ # is not available + \ cred_info = cred.get_cred_info\(\) # type: ignore + \ if cred_info and hasattr\(error._details, "append"\): + \ error._details.append\(json.dumps\(cred_info\)\) + \ \ @property \ def api_endpoint\(self\): \ """Return the API endpoint used by the client instance. From 4571dff9614843c6944c8568bd234c6ac5197218 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:49:25 +0500 Subject: [PATCH 02/13] chore: [Many APIs] Update gapic-generator-python to v1.22.1 (#13522) BEGIN_COMMIT_OVERRIDE chore: Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. fix(deps): Require grpc-google-iam-v1>=0.14.0 PiperOrigin-RevId: 726142856 Source-Link: https://github.com/googleapis/googleapis/commit/25989cb753bf7d69ee446bda9d9794b61912707d Source-Link: https://github.com/googleapis/googleapis-gen/commit/677041b91cef1598cc55727d59a2804b198a5bbf Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWFsbG95ZGIvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWFwaWdlZS1yZWdpc3RyeS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWFwcGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWFydGlmYWN0LXJlZ2lzdHJ5Ly5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWFzc2V0Ly5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJhY2t1cGRyLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJhcmUtbWV0YWwtc29sdXRpb24vLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJleW9uZGNvcnAtYXBwY29ubmVjdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJleW9uZGNvcnAtYXBwY29ubmVjdG9ycy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJleW9uZGNvcnAtYXBwZ2F0ZXdheXMvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJleW9uZGNvcnAtY2xpZW50Y29ubmVjdG9yc2VydmljZXMvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJleW9uZGNvcnAtY2xpZW50Z2F0ZXdheXMvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LWFuYWx5dGljc2h1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LWNvbm5lY3Rpb24vLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LWRhdGEtZXhjaGFuZ2UvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LWRhdGFwb2xpY2llcy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LWxvZ2dpbmcvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpbGxpbmcvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNvbmZpZy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNvbnRhY3QtY2VudGVyLWluc2lnaHRzLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= --------- Co-authored-by: Owl Bot --- packages/google-cloud-alloydb/README.rst | 4 +- .../google/cloud/alloydb/gapic_version.py | 2 +- .../google/cloud/alloydb_v1/gapic_version.py | 2 +- .../cloud/alloydb_v1alpha/gapic_version.py | 2 +- .../cloud/alloydb_v1beta/gapic_version.py | 2 +- packages/google-cloud-alloydb/noxfile.py | 81 ++++++++++++++++++- ...ppet_metadata_google.cloud.alloydb.v1.json | 2 +- ...metadata_google.cloud.alloydb.v1alpha.json | 2 +- ..._metadata_google.cloud.alloydb.v1beta.json | 2 +- packages/google-cloud-alloydb/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-apigee-registry/README.rst | 4 +- .../cloud/apigee_registry/gapic_version.py | 2 +- .../cloud/apigee_registry_v1/gapic_version.py | 2 +- .../google-cloud-apigee-registry/noxfile.py | 81 ++++++++++++++++++- ...tadata_google.cloud.apigeeregistry.v1.json | 2 +- .../google-cloud-apigee-registry/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google/cloud/apphub/gapic_version.py | 2 +- .../google/cloud/apphub_v1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.apphub.v1.json | 2 +- packages/google-cloud-apphub/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../cloud/artifactregistry/gapic_version.py | 2 +- .../artifactregistry_v1/gapic_version.py | 2 +- .../artifactregistry_v1beta2/gapic_version.py | 2 +- ...a_google.devtools.artifactregistry.v1.json | 2 +- ...gle.devtools.artifactregistry.v1beta2.json | 2 +- .../google-cloud-artifact-registry/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google/cloud/asset/gapic_version.py | 2 +- .../google/cloud/asset_v1/gapic_version.py | 2 +- .../cloud/asset_v1p1beta1/gapic_version.py | 2 +- .../cloud/asset_v1p2beta1/gapic_version.py | 2 +- .../cloud/asset_v1p5beta1/gapic_version.py | 2 +- ...nippet_metadata_google.cloud.asset.v1.json | 2 +- ...metadata_google.cloud.asset.v1p1beta1.json | 2 +- ...metadata_google.cloud.asset.v1p2beta1.json | 2 +- ...metadata_google.cloud.asset.v1p5beta1.json | 2 +- packages/google-cloud-asset/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google/cloud/backupdr/gapic_version.py | 2 +- .../google/cloud/backupdr_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.backupdr.v1.json | 2 +- packages/google-cloud-backupdr/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../bare_metal_solution/gapic_version.py | 2 +- .../bare_metal_solution_v2/gapic_version.py | 2 +- ...ata_google.cloud.baremetalsolution.v2.json | 2 +- .../google-cloud-bare-metal-solution/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...le.cloud.beyondcorp.appconnections.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../beyondcorp_appconnectors/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...gle.cloud.beyondcorp.appconnectors.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../beyondcorp_appgateways/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...oogle.cloud.beyondcorp.appgateways.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...beyondcorp.clientconnectorservices.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...le.cloud.beyondcorp.clientgateways.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../bigquery_analyticshub/gapic_version.py | 2 +- .../bigquery_analyticshub_v1/gapic_version.py | 2 +- ...google.cloud.bigquery.analyticshub.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../bigquery_connection/gapic_version.py | 2 +- .../bigquery_connection_v1/gapic_version.py | 2 +- ...a_google.cloud.bigquery.connection.v1.json | 2 +- .../google-cloud-bigquery-connection/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../bigquery_data_exchange/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...e.cloud.bigquery.dataexchange.v1beta1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../bigquery_datapolicies/gapic_version.py | 2 +- .../bigquery_datapolicies_v1/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...google.cloud.bigquery.datapolicies.v1.json | 2 +- ...e.cloud.bigquery.datapolicies.v1beta1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-bigquery-logging/README.rst | 4 +- .../cloud/bigquery_logging/gapic_version.py | 2 +- .../bigquery_logging_v1/gapic_version.py | 2 +- .../google-cloud-bigquery-logging/noxfile.py | 81 ++++++++++++++++++- .../google-cloud-bigquery-logging/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-billing/README.rst | 4 +- .../google/cloud/billing/gapic_version.py | 2 +- .../google/cloud/billing_v1/gapic_version.py | 2 +- packages/google-cloud-billing/noxfile.py | 81 ++++++++++++++++++- ...ppet_metadata_google.cloud.billing.v1.json | 2 +- packages/google-cloud-billing/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-config/README.rst | 4 +- .../google/cloud/config/gapic_version.py | 2 +- .../google/cloud/config_v1/gapic_version.py | 2 +- packages/google-cloud-config/noxfile.py | 81 ++++++++++++++++++- ...ippet_metadata_google.cloud.config.v1.json | 2 +- packages/google-cloud-config/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../contact_center_insights/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../noxfile.py | 81 ++++++++++++++++++- ...google.cloud.contactcenterinsights.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- 125 files changed, 599 insertions(+), 137 deletions(-) diff --git a/packages/google-cloud-alloydb/README.rst b/packages/google-cloud-alloydb/README.rst index 258140122157..70e30f3e7018 100644 --- a/packages/google-cloud-alloydb/README.rst +++ b/packages/google-cloud-alloydb/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the AlloyDB.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the AlloyDB.: https://cloud.google.com/alloydb/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py index ee41ffcc0a1d..558c8aab67c5 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.2" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py index ee41ffcc0a1d..558c8aab67c5 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.2" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py index ee41ffcc0a1d..558c8aab67c5 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.2" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py index ee41ffcc0a1d..558c8aab67c5 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.2" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/noxfile.py b/packages/google-cloud-alloydb/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-alloydb/noxfile.py +++ b/packages/google-cloud-alloydb/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json index bafdc61433dc..93784dc7f2da 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.4.2" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json index 50eb941ff80e..0beca3926d06 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.4.2" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json index d63c8b069fce..696ffb3efe81 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.4.2" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-alloydb/setup.py b/packages/google-cloud-alloydb/setup.py index c18bcf915931..e6d2db5157af 100644 --- a/packages/google-cloud-alloydb/setup.py +++ b/packages/google-cloud-alloydb/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-alloydb" diff --git a/packages/google-cloud-alloydb/testing/constraints-3.7.txt b/packages/google-cloud-alloydb/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-alloydb/testing/constraints-3.7.txt +++ b/packages/google-cloud-alloydb/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-apigee-registry/README.rst b/packages/google-cloud-apigee-registry/README.rst index f5c6d19ba966..46bbd8abe077 100644 --- a/packages/google-cloud-apigee-registry/README.rst +++ b/packages/google-cloud-apigee-registry/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Apigee Registry API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Apigee Registry API.: https://cloud.google.com/apigee/docs/api-hub/get-started-registry-api -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py index e51340f75942..558c8aab67c5 100644 --- a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py +++ b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py index e51340f75942..558c8aab67c5 100644 --- a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py +++ b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-apigee-registry/noxfile.py b/packages/google-cloud-apigee-registry/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-apigee-registry/noxfile.py +++ b/packages/google-cloud-apigee-registry/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json b/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json index 0df5d9cb9934..b2c5df756020 100644 --- a/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json +++ b/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-apigee-registry", - "version": "0.6.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-apigee-registry/setup.py b/packages/google-cloud-apigee-registry/setup.py index 0455b81466ed..ac3a98518fa6 100644 --- a/packages/google-cloud-apigee-registry/setup.py +++ b/packages/google-cloud-apigee-registry/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apigee-registry" diff --git a/packages/google-cloud-apigee-registry/testing/constraints-3.7.txt b/packages/google-cloud-apigee-registry/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-apigee-registry/testing/constraints-3.7.txt +++ b/packages/google-cloud-apigee-registry/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py b/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py +++ b/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py b/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py index 51d2795b9d6b..558c8aab67c5 100644 --- a/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py +++ b/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.6" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json b/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json index f447f3094ffa..161a57517820 100644 --- a/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json +++ b/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-apphub", - "version": "0.1.6" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-apphub/setup.py b/packages/google-cloud-apphub/setup.py index dc5ab0768181..31889c64d574 100644 --- a/packages/google-cloud-apphub/setup.py +++ b/packages/google-cloud-apphub/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apphub" diff --git a/packages/google-cloud-apphub/testing/constraints-3.7.txt b/packages/google-cloud-apphub/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-apphub/testing/constraints-3.7.txt +++ b/packages/google-cloud-apphub/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py index cf18a472a8a2..558c8aab67c5 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.15.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py index cf18a472a8a2..558c8aab67c5 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.15.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py index cf18a472a8a2..558c8aab67c5 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.15.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json index 15b695d1cc53..43448eb993ec 100644 --- a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json +++ b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-artifact-registry", - "version": "1.15.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json index 8d5ddafa8752..914e581f4fb1 100644 --- a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json +++ b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-artifact-registry", - "version": "1.15.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-artifact-registry/setup.py b/packages/google-cloud-artifact-registry/setup.py index d6c003064d1a..dd634ebfc206 100644 --- a/packages/google-cloud-artifact-registry/setup.py +++ b/packages/google-cloud-artifact-registry/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-artifact-registry" diff --git a/packages/google-cloud-artifact-registry/testing/constraints-3.7.txt b/packages/google-cloud-artifact-registry/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-artifact-registry/testing/constraints-3.7.txt +++ b/packages/google-cloud-artifact-registry/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-asset/google/cloud/asset/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset/gapic_version.py index 856a3fbea2a6..558c8aab67c5 100644 --- a/packages/google-cloud-asset/google/cloud/asset/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py index 856a3fbea2a6..558c8aab67c5 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py index 856a3fbea2a6..558c8aab67c5 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py index 856a3fbea2a6..558c8aab67c5 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py index 856a3fbea2a6..558c8aab67c5 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json index e6936177e858..211efb19c2ad 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.29.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json index 36476848d744..13d603d43770 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.29.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json index 751348e6ccf6..abb0badfbf70 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.29.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json index aa980dbc968e..2b27b5681d7c 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.29.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-asset/setup.py b/packages/google-cloud-asset/setup.py index 3b872e908cc5..91176b99b71d 100644 --- a/packages/google-cloud-asset/setup.py +++ b/packages/google-cloud-asset/setup.py @@ -49,7 +49,7 @@ "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", "google-cloud-access-context-manager >= 0.1.2, <1.0.0dev", "google-cloud-os-config >= 1.0.0, <2.0.0dev", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-asset" diff --git a/packages/google-cloud-asset/testing/constraints-3.7.txt b/packages/google-cloud-asset/testing/constraints-3.7.txt index bc8e34f1f281..2ecd9c5ac807 100644 --- a/packages/google-cloud-asset/testing/constraints-3.7.txt +++ b/packages/google-cloud-asset/testing/constraints-3.7.txt @@ -11,4 +11,4 @@ proto-plus==1.22.3 protobuf==3.20.2 google-cloud-access-context-manager==0.1.2 google-cloud-os-config==1.0.0 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py b/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py index 6d8247638d59..558c8aab67c5 100644 --- a/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py +++ b/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py b/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py index 6d8247638d59..558c8aab67c5 100644 --- a/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py +++ b/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json b/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json index b4fb12439766..0f3972263529 100644 --- a/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json +++ b/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-backupdr", - "version": "0.2.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-backupdr/setup.py b/packages/google-cloud-backupdr/setup.py index 4c0a00bf9ed9..505635e5f2cd 100644 --- a/packages/google-cloud-backupdr/setup.py +++ b/packages/google-cloud-backupdr/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-backupdr" diff --git a/packages/google-cloud-backupdr/testing/constraints-3.7.txt b/packages/google-cloud-backupdr/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-backupdr/testing/constraints-3.7.txt +++ b/packages/google-cloud-backupdr/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py index d1d2a9e60a97..558c8aab67c5 100644 --- a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py +++ b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.10.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py index d1d2a9e60a97..558c8aab67c5 100644 --- a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py +++ b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.10.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json b/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json index 38629334665b..2e341fc16178 100644 --- a/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json +++ b/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bare-metal-solution", - "version": "1.10.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bare-metal-solution/setup.py b/packages/google-cloud-bare-metal-solution/setup.py index a85c435fa662..46d1f95836a5 100644 --- a/packages/google-cloud-bare-metal-solution/setup.py +++ b/packages/google-cloud-bare-metal-solution/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bare-metal-solution" diff --git a/packages/google-cloud-bare-metal-solution/testing/constraints-3.7.txt b/packages/google-cloud-bare-metal-solution/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bare-metal-solution/testing/constraints-3.7.txt +++ b/packages/google-cloud-bare-metal-solution/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json b/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json index 87a7ecbfb05b..f730a69adfa5 100644 --- a/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json +++ b/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appconnections", - "version": "0.4.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appconnections/setup.py b/packages/google-cloud-beyondcorp-appconnections/setup.py index 996f832d0e40..4b8dbd1f425d 100644 --- a/packages/google-cloud-beyondcorp-appconnections/setup.py +++ b/packages/google-cloud-beyondcorp-appconnections/setup.py @@ -50,7 +50,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnections" diff --git a/packages/google-cloud-beyondcorp-appconnections/testing/constraints-3.7.txt b/packages/google-cloud-beyondcorp-appconnections/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-beyondcorp-appconnections/testing/constraints-3.7.txt +++ b/packages/google-cloud-beyondcorp-appconnections/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json b/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json index 68a1ece7312b..e1535607b299 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json +++ b/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appconnectors", - "version": "0.4.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appconnectors/setup.py b/packages/google-cloud-beyondcorp-appconnectors/setup.py index 3d48ea16b81b..397f45e7cd30 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/setup.py +++ b/packages/google-cloud-beyondcorp-appconnectors/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnectors" diff --git a/packages/google-cloud-beyondcorp-appconnectors/testing/constraints-3.7.txt b/packages/google-cloud-beyondcorp-appconnectors/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/testing/constraints-3.7.txt +++ b/packages/google-cloud-beyondcorp-appconnectors/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json b/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json index 59e696470f03..0b3067b40e2b 100644 --- a/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json +++ b/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appgateways", - "version": "0.4.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appgateways/setup.py b/packages/google-cloud-beyondcorp-appgateways/setup.py index 8411c3d09605..7bbfd1961526 100644 --- a/packages/google-cloud-beyondcorp-appgateways/setup.py +++ b/packages/google-cloud-beyondcorp-appgateways/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appgateways" diff --git a/packages/google-cloud-beyondcorp-appgateways/testing/constraints-3.7.txt b/packages/google-cloud-beyondcorp-appgateways/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-beyondcorp-appgateways/testing/constraints-3.7.txt +++ b/packages/google-cloud-beyondcorp-appgateways/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json b/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json index f5db07f151ea..e2e2d8f829d9 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-clientconnectorservices", - "version": "0.4.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/setup.py b/packages/google-cloud-beyondcorp-clientconnectorservices/setup.py index 0bb8fe434f0a..17ccc9f44bae 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/setup.py +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/setup.py @@ -50,7 +50,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientconnectorservices" diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/testing/constraints-3.7.txt b/packages/google-cloud-beyondcorp-clientconnectorservices/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/testing/constraints-3.7.txt +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py index 3106ac663ac7..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.14" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py index 3106ac663ac7..558c8aab67c5 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.14" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json b/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json index 38c198d87520..1aa87eed26ed 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json +++ b/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-clientgateways", - "version": "0.4.14" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-clientgateways/setup.py b/packages/google-cloud-beyondcorp-clientgateways/setup.py index 882ca60e9cf8..b687ce586e36 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/setup.py +++ b/packages/google-cloud-beyondcorp-clientgateways/setup.py @@ -50,7 +50,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientgateways" diff --git a/packages/google-cloud-beyondcorp-clientgateways/testing/constraints-3.7.txt b/packages/google-cloud-beyondcorp-clientgateways/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/testing/constraints-3.7.txt +++ b/packages/google-cloud-beyondcorp-clientgateways/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py +++ b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py index 49a0d50535a0..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.4.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json b/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json index 80eab354d271..7d9e59976e72 100644 --- a/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json +++ b/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-analyticshub", - "version": "0.4.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-analyticshub/setup.py b/packages/google-cloud-bigquery-analyticshub/setup.py index 52937624f0df..a5d5e9890f20 100644 --- a/packages/google-cloud-bigquery-analyticshub/setup.py +++ b/packages/google-cloud-bigquery-analyticshub/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-analyticshub" diff --git a/packages/google-cloud-bigquery-analyticshub/testing/constraints-3.7.txt b/packages/google-cloud-bigquery-analyticshub/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bigquery-analyticshub/testing/constraints-3.7.txt +++ b/packages/google-cloud-bigquery-analyticshub/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py +++ b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json b/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json index 539b0c69eb30..a25b5a29d478 100644 --- a/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json +++ b/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-connection", - "version": "1.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-connection/setup.py b/packages/google-cloud-bigquery-connection/setup.py index ca2277611b04..b5daac1263fe 100644 --- a/packages/google-cloud-bigquery-connection/setup.py +++ b/packages/google-cloud-bigquery-connection/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-connection" diff --git a/packages/google-cloud-bigquery-connection/testing/constraints-3.7.txt b/packages/google-cloud-bigquery-connection/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bigquery-connection/testing/constraints-3.7.txt +++ b/packages/google-cloud-bigquery-connection/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py index 6dccd9f0e979..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py +++ b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.17" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py index 6dccd9f0e979..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py +++ b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.17" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json b/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json index f9600737979c..0103e35cd88a 100644 --- a/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json +++ b/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-data-exchange", - "version": "0.5.17" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-data-exchange/setup.py b/packages/google-cloud-bigquery-data-exchange/setup.py index 219968fd7bfd..592e07bad679 100644 --- a/packages/google-cloud-bigquery-data-exchange/setup.py +++ b/packages/google-cloud-bigquery-data-exchange/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-data-exchange" diff --git a/packages/google-cloud-bigquery-data-exchange/testing/constraints-3.7.txt b/packages/google-cloud-bigquery-data-exchange/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bigquery-data-exchange/testing/constraints-3.7.txt +++ b/packages/google-cloud-bigquery-data-exchange/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py index 44e5c049e336..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py index 44e5c049e336..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py index 44e5c049e336..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.6.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json index 390eaf7b1f8d..8f3adb520dfb 100644 --- a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json +++ b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-datapolicies", - "version": "0.6.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json index 5a7576fe63ad..f5896d1aac3d 100644 --- a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json +++ b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-datapolicies", - "version": "0.6.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-datapolicies/setup.py b/packages/google-cloud-bigquery-datapolicies/setup.py index f04aa2da0d2d..aba580e42199 100644 --- a/packages/google-cloud-bigquery-datapolicies/setup.py +++ b/packages/google-cloud-bigquery-datapolicies/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datapolicies" diff --git a/packages/google-cloud-bigquery-datapolicies/testing/constraints-3.7.txt b/packages/google-cloud-bigquery-datapolicies/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bigquery-datapolicies/testing/constraints-3.7.txt +++ b/packages/google-cloud-bigquery-datapolicies/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-bigquery-logging/README.rst b/packages/google-cloud-bigquery-logging/README.rst index 784096be6d95..3ce4fad4ab7a 100644 --- a/packages/google-cloud-bigquery-logging/README.rst +++ b/packages/google-cloud-bigquery-logging/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the BigQuery Logging Protos.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the BigQuery Logging Protos.: https://cloud.google.com/bigquery/docs/reference/auditlogs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py index 186dbb3596a5..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py +++ b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.6.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py index 186dbb3596a5..558c8aab67c5 100644 --- a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.6.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-logging/noxfile.py b/packages/google-cloud-bigquery-logging/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-bigquery-logging/noxfile.py +++ b/packages/google-cloud-bigquery-logging/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-bigquery-logging/setup.py b/packages/google-cloud-bigquery-logging/setup.py index 0629c2f5a8ad..70b2f9f04aca 100644 --- a/packages/google-cloud-bigquery-logging/setup.py +++ b/packages/google-cloud-bigquery-logging/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-logging" diff --git a/packages/google-cloud-bigquery-logging/testing/constraints-3.7.txt b/packages/google-cloud-bigquery-logging/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-bigquery-logging/testing/constraints-3.7.txt +++ b/packages/google-cloud-bigquery-logging/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-billing/README.rst b/packages/google-cloud-billing/README.rst index fec21affd3dd..5e73700ff898 100644 --- a/packages/google-cloud-billing/README.rst +++ b/packages/google-cloud-billing/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Billing.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Billing.: https://cloud.google.com/billing -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-billing/google/cloud/billing/gapic_version.py b/packages/google-cloud-billing/google/cloud/billing/gapic_version.py index 3e0ea3b28f0a..558c8aab67c5 100644 --- a/packages/google-cloud-billing/google/cloud/billing/gapic_version.py +++ b/packages/google-cloud-billing/google/cloud/billing/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.16.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py b/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py index 3e0ea3b28f0a..558c8aab67c5 100644 --- a/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py +++ b/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.16.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-billing/noxfile.py b/packages/google-cloud-billing/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-billing/noxfile.py +++ b/packages/google-cloud-billing/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json b/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json index cb2b9e5078c2..027b84af0571 100644 --- a/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json +++ b/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-billing", - "version": "1.16.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-billing/setup.py b/packages/google-cloud-billing/setup.py index 0895701561db..00010ec2715e 100644 --- a/packages/google-cloud-billing/setup.py +++ b/packages/google-cloud-billing/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing" diff --git a/packages/google-cloud-billing/testing/constraints-3.7.txt b/packages/google-cloud-billing/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-billing/testing/constraints-3.7.txt +++ b/packages/google-cloud-billing/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-config/README.rst b/packages/google-cloud-config/README.rst index 4370f4cf8d90..59ec311afc0e 100644 --- a/packages/google-cloud-config/README.rst +++ b/packages/google-cloud-config/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Infrastructure Manager API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Infrastructure Manager API.: https://cloud.google.com/infrastructure-manager/docs/overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-config/google/cloud/config/gapic_version.py b/packages/google-cloud-config/google/cloud/config/gapic_version.py index 564cdfade642..558c8aab67c5 100644 --- a/packages/google-cloud-config/google/cloud/config/gapic_version.py +++ b/packages/google-cloud-config/google/cloud/config/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py b/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py index 564cdfade642..558c8aab67c5 100644 --- a/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py +++ b/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-config/noxfile.py b/packages/google-cloud-config/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-config/noxfile.py +++ b/packages/google-cloud-config/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json b/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json index 3ca31ba06e74..e9c423a602a2 100644 --- a/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json +++ b/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-config", - "version": "0.1.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-config/setup.py b/packages/google-cloud-config/setup.py index 957e5bf8ecd0..3b47d87bad25 100644 --- a/packages/google-cloud-config/setup.py +++ b/packages/google-cloud-config/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-config" diff --git a/packages/google-cloud-config/testing/constraints-3.7.txt b/packages/google-cloud-config/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-config/testing/constraints-3.7.txt +++ b/packages/google-cloud-config/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-contact-center-insights/README.rst b/packages/google-cloud-contact-center-insights/README.rst index b16247876d7d..4b3c42866256 100644 --- a/packages/google-cloud-contact-center-insights/README.rst +++ b/packages/google-cloud-contact-center-insights/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Contact Center AI Insights.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Contact Center AI Insights.: https://cloud.google.com/contact-center/insights/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py index c8313abd74cb..558c8aab67c5 100644 --- a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py +++ b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py index c8313abd74cb..558c8aab67c5 100644 --- a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py +++ b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-contact-center-insights/noxfile.py b/packages/google-cloud-contact-center-insights/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-contact-center-insights/noxfile.py +++ b/packages/google-cloud-contact-center-insights/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json b/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json index 634799fedfdd..53fac2587492 100644 --- a/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json +++ b/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-contact-center-insights", - "version": "1.23.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-contact-center-insights/setup.py b/packages/google-cloud-contact-center-insights/setup.py index c42006cbbb36..21dccee2b21c 100644 --- a/packages/google-cloud-contact-center-insights/setup.py +++ b/packages/google-cloud-contact-center-insights/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contact-center-insights" diff --git a/packages/google-cloud-contact-center-insights/testing/constraints-3.7.txt b/packages/google-cloud-contact-center-insights/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-contact-center-insights/testing/constraints-3.7.txt +++ b/packages/google-cloud-contact-center-insights/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 From 16e14c8d547864360dcab45d90e9e55169204fc6 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:50:00 +0500 Subject: [PATCH 03/13] chore: [Many APIs] Update gapic-generator-python to v1.22.1 (#13523) BEGIN_COMMIT_OVERRIDE chore: Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. fix(deps): Require grpc-google-iam-v1>=0.14.0 PiperOrigin-RevId: 726142856 Source-Link: https://github.com/googleapis/googleapis/commit/25989cb753bf7d69ee446bda9d9794b61912707d Source-Link: https://github.com/googleapis/googleapis-gen/commit/677041b91cef1598cc55727d59a2804b198a5bbf Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNvbnRhaW5lcmFuYWx5c2lzLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNvbnRlbnR3YXJlaG91c2UvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGEtZnVzaW9uLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFjYXRhbG9nLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFmb3JtLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFwbGV4Ly5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFwcm9jLW1ldGFzdG9yZS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFwcm9jLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFzdHJlYW0vLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRlcGxveS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRtcy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWV2ZW50YXJjLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWZ1bmN0aW9ucy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWdrZS1iYWNrdXAvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWdrZS1odWIvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWlhbS1sb2dnaW5nLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWlhbS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWlhcC8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWttcy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmstY29ubmVjdGl2aXR5Ly5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= --------- Co-authored-by: Owl Bot --- .../google-cloud-containeranalysis/README.rst | 4 +- .../containeranalysis/gapic_version.py | 2 +- .../containeranalysis_v1/gapic_version.py | 2 +- .../google-cloud-containeranalysis/noxfile.py | 81 +++++++++++++++++- ..._google.devtools.containeranalysis.v1.json | 2 +- .../google-cloud-containeranalysis/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-contentwarehouse/README.rst | 4 +- .../cloud/contentwarehouse/gapic_version.py | 2 +- .../contentwarehouse_v1/gapic_version.py | 2 +- .../google-cloud-contentwarehouse/noxfile.py | 81 +++++++++++++++++- ...data_google.cloud.contentwarehouse.v1.json | 2 +- .../google-cloud-contentwarehouse/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-data-fusion/README.rst | 4 +- .../google/cloud/data_fusion/gapic_version.py | 2 +- .../cloud/data_fusion_v1/gapic_version.py | 2 +- packages/google-cloud-data-fusion/noxfile.py | 81 +++++++++++++++++- ...t_metadata_google.cloud.datafusion.v1.json | 2 +- packages/google-cloud-datacatalog/README.rst | 4 +- .../datacatalog-v1-py.tar.gz | Bin 114688 -> 65536 bytes .../google/cloud/datacatalog/gapic_version.py | 2 +- .../cloud/datacatalog_v1/gapic_version.py | 2 +- .../datacatalog_v1beta1/gapic_version.py | 2 +- packages/google-cloud-datacatalog/noxfile.py | 81 +++++++++++++++++- ..._metadata_google.cloud.datacatalog.v1.json | 2 +- ...data_google.cloud.datacatalog.v1beta1.json | 2 +- packages/google-cloud-datacatalog/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-dataform/README.rst | 4 +- .../google/cloud/dataform/gapic_version.py | 2 +- .../cloud/dataform_v1beta1/gapic_version.py | 2 +- packages/google-cloud-dataform/noxfile.py | 81 +++++++++++++++++- ...etadata_google.cloud.dataform.v1beta1.json | 2 +- packages/google-cloud-dataform/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-dataplex/README.rst | 4 +- .../google/cloud/dataplex/gapic_version.py | 2 +- .../google/cloud/dataplex_v1/gapic_version.py | 2 +- packages/google-cloud-dataplex/noxfile.py | 81 +++++++++++++++++- ...pet_metadata_google.cloud.dataplex.v1.json | 2 +- packages/google-cloud-dataplex/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../google/cloud/metastore/gapic_version.py | 2 +- .../cloud/metastore_v1/gapic_version.py | 2 +- .../cloud/metastore_v1alpha/gapic_version.py | 2 +- .../cloud/metastore_v1beta/gapic_version.py | 2 +- .../noxfile.py | 81 +++++++++++++++++- ...et_metadata_google.cloud.metastore.v1.json | 2 +- ...tadata_google.cloud.metastore.v1alpha.json | 2 +- ...etadata_google.cloud.metastore.v1beta.json | 2 +- .../google-cloud-dataproc-metastore/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-dataproc/README.rst | 4 +- .../google/cloud/dataproc/gapic_version.py | 2 +- .../google/cloud/dataproc_v1/gapic_version.py | 2 +- packages/google-cloud-dataproc/noxfile.py | 81 +++++++++++++++++- ...pet_metadata_google.cloud.dataproc.v1.json | 2 +- packages/google-cloud-dataproc/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-datastream/README.rst | 4 +- .../google/cloud/datastream/gapic_version.py | 2 +- .../cloud/datastream_v1/gapic_version.py | 2 +- .../datastream_v1alpha1/gapic_version.py | 2 +- packages/google-cloud-datastream/noxfile.py | 81 +++++++++++++++++- ...t_metadata_google.cloud.datastream.v1.json | 2 +- ...data_google.cloud.datastream.v1alpha1.json | 2 +- packages/google-cloud-datastream/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-deploy/README.rst | 4 +- .../google/cloud/deploy/gapic_version.py | 2 +- .../google/cloud/deploy_v1/gapic_version.py | 2 +- packages/google-cloud-deploy/noxfile.py | 81 +++++++++++++++++- ...ippet_metadata_google.cloud.deploy.v1.json | 2 +- packages/google-cloud-deploy/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-dms/README.rst | 4 +- .../google/cloud/clouddms/gapic_version.py | 2 +- .../google/cloud/clouddms_v1/gapic_version.py | 2 +- packages/google-cloud-dms/noxfile.py | 81 +++++++++++++++++- ...pet_metadata_google.cloud.clouddms.v1.json | 2 +- packages/google-cloud-dms/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-eventarc/README.rst | 4 +- .../google/cloud/eventarc/gapic_version.py | 2 +- .../google/cloud/eventarc_v1/gapic_version.py | 2 +- packages/google-cloud-eventarc/noxfile.py | 81 +++++++++++++++++- ...pet_metadata_google.cloud.eventarc.v1.json | 2 +- packages/google-cloud-eventarc/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-functions/README.rst | 4 +- .../google/cloud/functions/gapic_version.py | 2 +- .../cloud/functions_v1/gapic_version.py | 2 +- .../cloud/functions_v2/gapic_version.py | 2 +- packages/google-cloud-functions/noxfile.py | 81 +++++++++++++++++- ...et_metadata_google.cloud.functions.v1.json | 2 +- ...et_metadata_google.cloud.functions.v2.json | 2 +- packages/google-cloud-functions/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-gke-backup/README.rst | 4 +- .../google/cloud/gke_backup/gapic_version.py | 2 +- .../cloud/gke_backup_v1/gapic_version.py | 2 +- packages/google-cloud-gke-backup/noxfile.py | 81 +++++++++++++++++- ...et_metadata_google.cloud.gkebackup.v1.json | 2 +- packages/google-cloud-gke-backup/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-gke-hub/README.rst | 4 +- .../google/cloud/gkehub/gapic_version.py | 2 +- .../configmanagement_v1/gapic_version.py | 2 +- .../google/cloud/gkehub_v1/gapic_version.py | 2 +- .../multiclusteringress_v1/gapic_version.py | 2 +- .../cloud/gkehub_v1beta1/gapic_version.py | 2 +- packages/google-cloud-gke-hub/noxfile.py | 81 +++++++++++++++++- ...ippet_metadata_google.cloud.gkehub.v1.json | 2 +- ..._metadata_google.cloud.gkehub.v1beta1.json | 2 +- packages/google-cloud-iam-logging/README.rst | 4 +- packages/google-cloud-iam-logging/noxfile.py | 81 +++++++++++++++++- packages/google-cloud-iam-logging/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-iam/README.rst | 4 +- .../google/cloud/iam/gapic_version.py | 2 +- .../google/cloud/iam_admin/gapic_version.py | 2 +- .../cloud/iam_admin_v1/gapic_version.py | 2 +- .../cloud/iam_credentials/gapic_version.py | 2 +- .../cloud/iam_credentials_v1/gapic_version.py | 2 +- .../google/cloud/iam_v2/gapic_version.py | 2 +- .../google/cloud/iam_v2beta/gapic_version.py | 2 +- packages/google-cloud-iam/noxfile.py | 81 +++++++++++++++++- .../snippet_metadata_google.iam.admin.v1.json | 2 +- ...et_metadata_google.iam.credentials.v1.json | 2 +- .../snippet_metadata_google.iam.v2.json | 2 +- .../snippet_metadata_google.iam.v2beta.json | 2 +- packages/google-cloud-iap/README.rst | 4 +- .../google/cloud/iap/gapic_version.py | 2 +- .../google/cloud/iap_v1/gapic_version.py | 2 +- packages/google-cloud-iap/noxfile.py | 81 +++++++++++++++++- .../snippet_metadata_google.cloud.iap.v1.json | 2 +- packages/google-cloud-iap/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-kms/README.rst | 4 +- .../google/cloud/kms/gapic_version.py | 2 +- .../google/cloud/kms_v1/gapic_version.py | 2 +- packages/google-cloud-kms/noxfile.py | 81 +++++++++++++++++- .../snippet_metadata_google.cloud.kms.v1.json | 2 +- packages/google-cloud-kms/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../networkconnectivity/gapic_version.py | 2 +- .../networkconnectivity_v1/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../noxfile.py | 81 +++++++++++++++++- ...a_google.cloud.networkconnectivity.v1.json | 2 +- ...le.cloud.networkconnectivity.v1alpha1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- 156 files changed, 1735 insertions(+), 195 deletions(-) diff --git a/packages/google-cloud-containeranalysis/README.rst b/packages/google-cloud-containeranalysis/README.rst index c4973eb16477..bedf84bcfe83 100644 --- a/packages/google-cloud-containeranalysis/README.rst +++ b/packages/google-cloud-containeranalysis/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Container Analysis.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Container Analysis.: https://cloud.google.com/container-registry/docs/container-analysis -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py +++ b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py +++ b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-containeranalysis/noxfile.py b/packages/google-cloud-containeranalysis/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-containeranalysis/noxfile.py +++ b/packages/google-cloud-containeranalysis/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json b/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json index cbceeefe0d27..07f9c39e95c2 100644 --- a/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json +++ b/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-containeranalysis", - "version": "2.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-containeranalysis/setup.py b/packages/google-cloud-containeranalysis/setup.py index 4bf537f9f883..41181d77b483 100644 --- a/packages/google-cloud-containeranalysis/setup.py +++ b/packages/google-cloud-containeranalysis/setup.py @@ -51,7 +51,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-containeranalysis" diff --git a/packages/google-cloud-containeranalysis/testing/constraints-3.7.txt b/packages/google-cloud-containeranalysis/testing/constraints-3.7.txt index 0126d46f7f24..4de9b4569488 100644 --- a/packages/google-cloud-containeranalysis/testing/constraints-3.7.txt +++ b/packages/google-cloud-containeranalysis/testing/constraints-3.7.txt @@ -9,4 +9,4 @@ google-auth==2.14.1 grafeas==1.4.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-contentwarehouse/README.rst b/packages/google-cloud-contentwarehouse/README.rst index 0d477bed5734..7d9fd31e40d4 100644 --- a/packages/google-cloud-contentwarehouse/README.rst +++ b/packages/google-cloud-contentwarehouse/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Document AI Warehouse.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Document AI Warehouse.: https://cloud.google.com/document-warehouse/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py index 04fd3b965904..558c8aab67c5 100644 --- a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py +++ b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.7.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py index 04fd3b965904..558c8aab67c5 100644 --- a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py +++ b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.7.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-contentwarehouse/noxfile.py b/packages/google-cloud-contentwarehouse/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-contentwarehouse/noxfile.py +++ b/packages/google-cloud-contentwarehouse/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json b/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json index ff016d747a0f..3d6fe0e86ed6 100644 --- a/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json +++ b/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-contentwarehouse", - "version": "0.7.13" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-contentwarehouse/setup.py b/packages/google-cloud-contentwarehouse/setup.py index a04ce63bb651..faf02ec9e324 100644 --- a/packages/google-cloud-contentwarehouse/setup.py +++ b/packages/google-cloud-contentwarehouse/setup.py @@ -49,7 +49,7 @@ "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", "google-cloud-documentai >= 2.0.0, <4.0.0dev", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contentwarehouse" diff --git a/packages/google-cloud-contentwarehouse/testing/constraints-3.7.txt b/packages/google-cloud-contentwarehouse/testing/constraints-3.7.txt index e03d5841585a..eac5124a8d52 100644 --- a/packages/google-cloud-contentwarehouse/testing/constraints-3.7.txt +++ b/packages/google-cloud-contentwarehouse/testing/constraints-3.7.txt @@ -9,4 +9,4 @@ google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 google-cloud-documentai==2.0.0 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-data-fusion/README.rst b/packages/google-cloud-data-fusion/README.rst index 9dc1a42bb6bb..3af574df8587 100644 --- a/packages/google-cloud-data-fusion/README.rst +++ b/packages/google-cloud-data-fusion/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Data Fusion.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Data Fusion.: https://cloud.google.com/data-fusion -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py b/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py +++ b/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py b/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py +++ b/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-data-fusion/noxfile.py b/packages/google-cloud-data-fusion/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-data-fusion/noxfile.py +++ b/packages/google-cloud-data-fusion/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json b/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json index 961112da7b31..fce0307055b9 100644 --- a/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json +++ b/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-data-fusion", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-datacatalog/README.rst b/packages/google-cloud-datacatalog/README.rst index e4c532faeb29..5a1715bbefe0 100644 --- a/packages/google-cloud-datacatalog/README.rst +++ b/packages/google-cloud-datacatalog/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Data Catalog.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Data Catalog.: https://cloud.google.com/data-catalog -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-datacatalog/datacatalog-v1-py.tar.gz b/packages/google-cloud-datacatalog/datacatalog-v1-py.tar.gz index f58e136e43ae31b4fccfcf89dba2a2b1d5819a05..3dd1e722c6385e3c353bd450f3825e001aa0c4a3 100644 GIT binary patch literal 65536 zcmV)2K+L}%iwFP!000001MEC&ciT3y{mfs1l|NW=P0F&Jq}Pr2u3{^xwvOy;Db49= zQW~Nl2{lP@`LLt*bbtGu8GsKx9jA%gJ!|$frhvgzd-8<-!n637-dl&yo*eA&9X#7R{A#bY|Lobbuh^5%Ps;L>B`J>?`zlr{-2``6 z{eS2)T9W@|r+xamEYoT`M36;9zI==|KTCZfA4b%^8>^VTQflH0C{fvnotEms+815x_`Z*2{a+@%Yt{!Yr~|A? z9P5y1NVABwGk^|L3Dr`Ch{tjq=6*bZM{Js=FtBFRQ(>Zf;dlt>Oo#x-Q$f>!65_iC zQbD(f#efzGGf*Qrp4q1LmLTk|fph`8%iU`CD+gWnse9v*Oq`LpX-1@W zrqqUF+f%V<0t-ZvHaTE%rfJ}#l7M~sKB2SzU3rSCIlW;r1cqMS$T-coFT$HE7jz5x z5y{9|sDNf16iWdLWf^HmU^M&%acIK;NExdzfI%e=8-VW zf(TV8m>OFn5s7dlLQg_54@c}q#0d-`*`;4H9LX3s=g(Lq;y@-;=UCQTnNH`a+=VW- z6Ba3eAr(~6dd0wRp{2^SwUANFz$^kQhplv@NyyLYp2;x#VEvpwgw9hVVGn)fT^}7WqwJQ&;L&<=!0Z4x z7~ZhwsM0pP{hg{4_~nU8DX4PT5nkt|P@r z3^T$;3KghOrYa^|%VN-1RF&*VIqMyICS)a+JCSC zzZT5nG3ouz4t5<&aG%`sz~rzHkpt<;&JL4f{54|;p70wn+GV#>0Yx#IDGne6P>=h- z92N74Kraksa~|EW*Fh>x1=1Odu?+Q4l;>q}4CWwqnGcNewL#%XFopt`Zg?zJmJmw= zpcA@E&@-(x*s;$w6O+uFGH=R5gysnwf=9YWQefbxiiIj=+7gjw83b9%!5yRY)Hr7Y zA=1Lz*`YDKm_e&C&-`?E1rQs@DwwAWxrcoLAtP`C4*L-zaR6x&kRd)qzVsyeEg0@t zPO_LVYG6PMQqb;J`$6h45I88A1TZ84N&qgz>dPSVfqxbEYJ+1HqXO@;$KUXP5h$iZ zR53u*(3K45;jCaY2!(@IX4cP!!KWsjQ&_TMTw^(fk6a_D%h74yhDC1NT&|wM=G{pzRqdq#hX`G zsJ~M=0R?ZY5F~{{BYV){FcdK`JdkOMJ>*V% zbssf=qea7SFs4BMTE&U)L^h0*M;cd1;t)oyVu(T-drI#j^&IqF)F(;E;IW7kpfYVX z$3`8zA*x9=vJ(;Un4)&bVK5Q*gmzs+0WA_8+6)JE%5eo@b%cq^c$O1x{3PT(nNOYp z&|IUF(7q8!u-OkJ);U6wqb1C9zfID{Awfu;o7Pe_f3`T7VNuxDDN>>p^Av`qU&IgV*T*S(skwKJ% z<{Zs+&$QB_g`lR*!q_|MV4U0$X~FTRIAwQOEZk32#e3(zYF;_C z6W1mI*=LbVl=(y9)z|96iRpt9gillgondK4LdZZy=8l2N$m`9qE{%DZV9M#<9OO-k zGTjLKbaj{PILGHqM0!SL^_oUlYb-)Lkm`S@$5GFl^-~DbL0;NeZUbg?hQ6>q=erws zaOewa=by>bCH?-=OwQ9~@Bxr#`pKfHP&RrgCZOCtW|RJIxvE}524;7@RxGq7f z6>2^OTA6d~vSE>aEyngd&w`m`#3vNJz}uRP7FU~akcOisxC@pC8Cz!sX7uRbkuJSb z0$_Rit}yGZbWp)=+UkWCO7AMk9k3I7Ur0JuScp>~2dNL@OkB;SRFr|{jwg^Gv^SRH zv4}~14M*mjSk2HBnpRDUFFJN5IqhN^VCvU8K&4C zWCj&>D(x{%G+a(t*P@5Wsc7qYm!-xy^r~Vifn__8-0UnmQ%a05;-!*|CRb=0 zvtHQJGd>l9sTh87Vq+P~U}!hmzK24DK(@HSDPeWuG;)x%I!y?;Y%|2HjcdY+EJ8ZQU*8iXE?YAD+{~zMnV)l-W){aXvEKA4s zH&|kAL2?q!VwhZ}Y=3Y6Fn7RbXD8Mc)SgLCglMB#NK5#jylt2;!5>qz%YM*Ho}kHl ztd0ORQ&nqx3m9^zjW$v&|D)!CwR!^lBG{d$z`;w*e#_-ag9Jj0UYP(CYDjBH==Gyw zHN?PynGeA{5KK+pgp?A*;$NA>DJ;Zt z;{#}&f#2dRkxyb1CV+z5SfXdzWr-T6w-Dh0%Shsy)sWmz$*i0@7;_Z>*aeZY*6y=z zzs6p)``!L7;CS1G8N-_ad)vOeZ1)D;PM@7$vXk@PX?M^)@4>H^tlj&Oec$b!!t_s4 z*nxN+Q%VzK&W7$9dDa(Vj({SB6h51WlMLs*6YxE8Nb7m!;xRftz~ak5rpB8u4GOxk zOqQsU{0$c}!NcZ1fi>nWnP#c znVC~T67mzpvD$(2thSrKep9~wPx;!~tGu@=@B5Ya19*RLStoBUFFU<~d)mG1oD9w{ ze}taQh@1=fTX$VlUDt(-h-1Ry@F7eAL8f&`LeI|Mb}ro)=WlwaE(onZxNLWOgTDK+ zd)5I&%gCFohI2^Bu_f+1q#x3nb_S&zp(YDz;p@iD5xbbbvdT|D@?hl>I zewTPs8~WV4K0e;xcMhDrnyJ5N55DUo$7;CmQ`=>ERtImmVoybhp4j1Q85pPn_j~aD zy>;4o*?x02$mg|{eu;sW1uY>%HwsjUC<|qpbJ{~)%YOtj?7~z`g?9~E{;i1Jp#oJ) zYE-d>Uc%2HNy(xS&P=KxI$t(PhQ_0ZsNabjBFumKz~lTKEG8Ddz?sEJM2QyuKPvRs z_3Y`m)VYSP#}%kRfFb`X>Nzfzs$n*EX{{5}8ZsEu)lUFGsF0aiG{iq%6xG=KU8`XM z?F{)-H{I^CHP~Q+N1fGbmsv%6 zf#CU}^Rc2{mR-(+LUErTE=ncN!g|pT*zRa~lts1;6p4i*kdj&6(p%5XinnraTFqr> zazD%Ew$7c8om?qmZy6>Q$X7rS2Wu;FZ@E&b5(k~R^NW&UeVaN*EkH}czuUT^khw~D zJV_dj5&=wIj(;nDkwIQuo)6AX&d=NzZ(hCxkC=PM?(2)Q&TDY@ZH(NtqjiERk^in= z8+SRPpX}EAFXoIE9OEDNOOQBm)HuX!8`Q-vIp%P4yUzbvPHc-6XA^L|)or5cs22ZDgFB2=I5MjaxyLqmF@M>mJz$g`G{0Kq-JhH8|8ApS zzuIMHNzm+7C$xU8XBh_X(s2**0gxry8Pm)~0YK?GmomPhrpfYvQ>&DXYje@3V)J|N zb?~YBB0ZZsuF-7H)HHBMxq^h!)l&7VH7O7eS=u776AM17ms&*0Hv_vRUIT|xv-74m z!-GJtsf5C?p^6Wcrbq7I`P#Vl^SflH z{;vOZqyE3g$H(|m+g%#dE^W0Z$AITGq^sStZm(0|(S5#OorLTx(r&n*o#OInYUODs z8#$puo19is5mRm9?9-~MES*-0w^+xdypuQrv;W(1%X#|D*^9lFQP6Vh&LkJ5b2_MC zUu-?sHC5U$?lhYtH}|?rWp?BjkcNNya7aY%v1HMPjKc>0(7dB?Df&kiO=3R68Yrvg zS0D<#sK4N@Xu)-bKrmC%QyN3(N->wMi@q*miDx>pv=RXeubI2EFc7amYHtLn#QTO~UHre(Bs~S=!M11$Z=;0SY{#S0Fpl9v%Dm=%#Jq%M7eFu%(@jVdC#r;;li@cfQkjTH5{8?5JWA(b=73uLWi@x(d!Xe zHj!l;Syg$UM>y|!OjNY-3|6J4x^B7PsmhcV6U<5*D6el?G;M5P{_=|9GVf0iW{LGV zhiPj*7Gq!U=*{&SxXIXLK8dr6(32RyzmyddpJIB}51Le%HNX0cT64w2p(cy_%D z;fgp`adM1jAU35bni^ZTuB6iTTfhqW<}If!7dil}QC46E8V0>N8)rC$k72?!1fk=` zk={0wW)iJi^mL0553Bg|$cEMKF;$o&r%K#L4(!s}I&z9iYmK|w-3?J<)?}4!J|#QA z<^9#c$fwini9VMBvx+o}adOWvHsYxsv$b!)Fpn6~4?1%|vcbKzBpZ*VC+SSA5xhSA zO-CsHmFWZa5PP$HCcHM#!~FDGz>J;EZQyKDC)&!G6P)%Gm7<->Zcom|MTBL~oA!V{ zh5Kf&WwijPlFsr3^qs+oj#WWcMc+Z?hYr`~2%pTQRV?|lH{$=KXZiexo|SygKJNeh z?;-s6`2FugJnQ7|x)LTguKPKT0c}42v)5`JES~>)x_|ie@%+z2Jl5j@pvMD1U*Z7J zpRL%B&qqD${68*jeXb|@`*k9*61zqJS8kMe(j=l=4?dN)!K z1!r!`CvLz)Jfq;^vN!kTulnYeYR0%R|2uf{Y~py5_Xvb9Uf-V?iUmS45|6&>hin8iN;4Ixp8cSe%2j z@kI1%EMQwKiuokqN33@aT>GJOX&HLD1lz&QyrY$H*hjTbt8ysL(l;gGkvQNrxIa49 z4M1}c#z|(2*Q5>D-v8p#N2RNRttZ^Al(=*- zop5~D?z`p|l=hp!cW%3TZY~X2DUCJ4SdHZ+bS12fjMQIwyNb5RlZ~LoPI{tGP2=`{ zQM9ooMNGW5Wg`%1j5`%R@%Uo_4I?*!<5s$hcM8z89Gf6xk>X8X3BBOi*+uz&lx&w; zITgkk1g|r^TVQb3KbhhUR6YsUTE1drKFM$(nYaOGk~nuI8hJk#1UKN5*BYu{1tM3V zuQ+|^uD@8XbpHyzC3hpIgK>qHPzNcR7NP%x&F6@_C$2PiOY>upJaBGWIS~BH)6HnO zzx4I*`i92R@7d}jyYf{yiL;QxW6_^57hF*54UH8V%YNR@h~DL%r!vr$<-^<-JSUf( zQ@7iDdG7wRPaoInleo3g9$kGKX6=a8ikmIzu-fhtBvOWOrfX)pu9|!KMXU@x8F9Y? zZyWf3m>XE|5?O%%y+UMvaM|s>0x~i5Iin0@T%R8To+crm#^}f>1Xu0i+=&S5s5QIH zn`Ys)o5)|qam$<>!PG(0*C2R-Uwsd+VASA^#`*}34fQ)~?0O{IVc1 z8l0b=AL$Egh!Ny@c?d>c^}CfTgy_rB>Q__whf^eYP5=Nb6u}K#MFf8`7?(&p#_E%&jOVt)!>kGLXKC3?DAU> z!>LtSgVW9tpH%T$Yn!cW04(T^3nq$i6e;|w15X#?b)Zv~=*uy~^18$n7+(P9x8>wl z?I2I-=y)K2FL?Fo2vTQr@#<1H<|8(9%M9Lx1i9BJL$fO{I0B6Ged-%=%n$QPSmk0> zZ8La9vuiqZbLhJ6Xs7Q2Ja>x;AYpffLt z^>CKT zd-OkU+m9{JoDGMA4Uv$9F-dR$(z2$vzx$I}7oe(8016-o0%S3|EnW(B$;$j?R#sM4 zJoJ&%(;MKU|GJ1I}H%y~0Dz7ndKeuYS3@08m03as>t?u4y&{}u_f zz5Z{X{+}0d{sL(j+y#faDs+8Nc}IVBXKRnF*vav6SlwfC_T&+KZ9Hs|hw;z}Yi0Ny z8z)5RUFz~||5iBK-)LS-FejKt^tTnsPzh@OH!_XC^{SHg*Xy^RVx5arU3i$lXzOf2 zo7s>rQk{2a5AI{s08`U;YVSVEN+%>T)%6m>sP&|EKrW>*CnEV9VddWj&TmLqDwLEz z%1hx{ARWf?q!(h`v z%5sw;yJ#g#Mbks%^#S#*Z)VeK>dqYY4jLqf_HaHk%V;^0ANQob@7N(rS0wjtl+0AB zH~j%y9FB=N(PM*(_!~B4-bfbr9Lva28{<&2;^IA{;kuj6nPO^oCcV*5@_!0&6Wrk4 zR!0W?!6S>A>u^AYLZ^X28^_0`J16XVY`2F(L&wJo?uqMG(b<4|%ONJ(9wnfeKwNrm zHDJhlyI%O{2E`&q%)<%6^@UWK;9)3LS&FJddcDb!qLoH!uLWQi2GYB6Lxm<=@0rwx zib_P9ZgHLmSra=*&0}IH#%>2*%jSKe$W*E?sM<+SOj_hrm#m(;x=sJh?W4-a+izN! zs+|+4Dv#~F<3jg^F4EOrVwp5HsY1gkhDt1<%IlM@OtDHlDia2)m^t)Wo7xd?K8i7! zUgfZYu{pAndDu(2+WAA{X@Hr^xZY#ER(?%sK;?H_e@Ggk((J2U()VScYn)I?U%r;E z(0R>jSo3|2tx|WrAp)c=hb&nra-3D}buacn6!Z0G&bqHDpG`n4$$b#BR7?TU~aI1BU&5UtZe}H*N#_@O1Gn#Pk=;gDsfg^ABv&F!G z7kE)r;AMV+pPoHS7oh9LfzSzY0V}qx{r;u)d(x8l{gbbvjq6UQ2?^-6xUfcJ*M zlaTj`)Fp#SIp)C$@-(E}M6^BD6%;Gl8tAsA}F3`wb0m@)m%n>88WCuBFE6kKR+qo0XO_>=yK8Qy?#tdEw zqMA7&FkF;pN-EvvR6?!A~(e_ylt#RvQdVU2I$Bm6j%`F*DRVR*12ha zh|+igB=8}nxiP(4yH6|@cg1|uC?KqWkTsmiZB84~N;9!s@fD8(YEXulQV@7) zy{?x+zCC=gABU7}$MjmvF-A>}aimAI^Z}ELnXno30#(mwc9bum`>eDuWV-E2i{$Fu zKxviGN`xG}>3TkYB+=xjG+|>za&5OpPn8%DcD?-r+NRNL`DuWe)K5 zn`L%$x5mv~Q|ORSU1sXlJVpD|q3OEGeLp@X_$K=c=(6X#_;?M_L$K(tm=Wf<&cb`Z z%bkaLn%8Lh`x?Qfy7z81d1YjtNl-1?YUZ{B#qL~nccf8X$s^ENy_si9;_tqT{$fIE zJf*QSN*fPe(cA(BvPSPY6TII=It?MvfDV!Ia?%0z#gLBUJ!5sTl2I@E$J(C`p{w)Z z!@W2A*2^^sQ-aawsn{qzNMUc9(1d-VT77Z+RC&4$l+lgY-{Vx9S&OYqt|zOTtY3-2 zsVRbXkA{qLp=c5;J#7Q&BYWt{!vHEx>3^()m5U)lI2mJqnq48fYes^q!h6f(onjV| zj80}F+X2?gbS>f0b#cDPiFw?g zOj>#55Zf@~cG6fb$15eWxE^1G^9#>=WkvO<5AxrS(+y=xPeMCW3Bs3w6bThqlO%kZ zN)suYEm8Q|wp6j0liI{e6S!~Xs)}4`gL|xmG$kSTE*Ft?av;JX{8pQ+Z11Q=753ld z!HU%66`rIb*Q?exHI1B0+tH+Ka0)FoEh;>SOOY}wkrd4Ig2^gauA|m0Li9@w6L;(m z79ra<#kRGGiD$iSD;X{GXRX1@F2UngdpzX{PjIIu3$Vg)K*G?56@4K`imUxvT>b;> zph!7T(oJpy#OJVfx*bre7j=!B<_*~Sz~gS%4Ut+lME-Nb1w1{vUVdMNq<>kAbj_Xk4j z#JI*XLsV(dys)Qr+_t$mU3>1(<)}P z)7meoBy~@nYrNH`#7=bV5UO|gIhB=`UPz#%#l~aXHMn3hbC^gmqp2PUhfsuX2aeuG zBqv~s=Pwo3$u_~|p^wt^P#=(bG0I|sO{SeLDC(W}bUI)21Z0*?He?f?;n9RA)R4Lc zLR4!cUm@M3`cn5RY>kEu1SIa9iu#3j{iMXL9I}+*_fn8`%rx*KJeWeZE4Hk&w&#V? ztu?kXu^Wp>lXJ_rpgKCK8rR|$6VIlLY1Xb=J@Dtt_7JnCdcWyYv8^Iek_%e13@LF;V(;A+`_W{D)^pi&}>4v#m z-1>Lx(4*kZPILDZdu!W{2~mEIH9E#L(x>!+dF^U~dHGf2Ps%QC%5@}Du%7cI<6^|` z>k+sP`6^pHoMo_F(~CL@8@ze_S;vf9bb4gWP4zj*r@ubEbggs1Zyi!5L2K!6mDn2R zNW;`NSn8Cd|DcHYWaWIsrumppf&pGr&#dsMy!K{lTyn4Q+L0&Z-Ya>ON3n{lE}F5z zWNExJImZxZ=^Vx#rM?Ati0597@vx^1rWfb3RUR%KEviyUQOb?Nw;XHJNR#=pb0ix= zX>!wxSye#ORh`NJ&ufo)s;KrtONj^u%ia4Ov$Ukx6?n?OS+BfZYq3(|0dz5thlFpY zco;@Cs#u#ptdX>?@=T9u;K+t4u$bqG)7eJm zuawaCETsO|Hk^f2=Srqvr%yztavarj>X8WZy*FC|@HczhQEYkFXaB^$(68&kHB~&y zo<@^sl!13*a#d`ja#pqkZ&ab~i5i!rgJno)p-}s47S-$_@$Ew5rs7JHA`|;opEy3= z^PS9s^>ipC79M{;8?tQ5(XgoXVI|}o%Hl(yA+9KqBKdnWVKTXwL^s!5;C}CmhIRjy z(^r!b_Wuy(DWj`4S>kS_##$1sv?NFlS-wGGEeUH$SWBYm1hOj{3g@zTI8i*nQlK(| zeul{X&H|Ij318;V6DKW?y%T+yY-R$m%mQ~Ri#=K=*e1XX$tbb(CS+h#gs|E8nP_0% z5OacM*Xm9u`PB*70`wixs+Y_F6;h?O1?xr@ znQRKcq_L%!f8T|g;!HpyVeDnCDg&wJzE*}K>GN-Wp7ZJ9;XDYEJ*vARz%d5oI_}+N*nj!m3m;ea{^AbJ zAUe_R4DUq&E?)&N=nX?52m5dhjm(M3G(n{wF1)F@=lVc31)?Zc8LX*JaVHoY>YRVL z8aPql{2c@OkYAE}Xc-x)24Nq7P$G4c6JvM+N30h?f~XznHhz8g@xukse|<9`ow{|u z(ful^ks>uk=!eZR!$DkZ$~>SjDwu89A#S$e`$P#mbzXasf43kPCoDic1DTgF`74hF zOw#~S2SlG)th3oLVFmo8ptH)`L(a$YP!McKef*a`*;lZ`k6=)bV_Ho7q%ZD8lh7yJ z0;Q7=+QPzGfLy>dI{W$TC&f&eto-k|T^KJM9*Ltnb8vhS1I32FT)n#-zxfD8-sS7@ z`NhTMr%&UH_wTMhzJDu$27ecNFprBUi2zK^D3@v>wiQGrTDdnfKe|tBrS)R!g|kOw z^_b@z0HXTi(~MI=P_EG{?(&JFKCZ;r8(a?vl(z6wL( zl2QfYG{W#fB0c(;jy?qkoHP0>zyM8xK!={b`-(q0$Yx(@+nkplB1dBH zL{8Qg6j_)&py6r#g9$g&=Th9QeN1I?GM~Wb+QNEvCs)O8%<dzwg*27$HbHvza9Wn;^{Q2tjONZ1$ z_9(fEfOcSQ<|7|JCNToQ?2}0lPEn4auJfx8CoiAB_-Q~f8v1-9DG9dD*r7J1T3u14 zAJ}jl)JF7Pbxr}Mm$NHhkmY3W=bs z4*wP#djuTvR&ld_=waYJsQ6o?uY>eem2D*miK&yJVD>?2r_?TkA$rai#s&s?NZnez zxA8YP_h54`G0ui|>IlG|qNC$7J`ps0zCs$sib?95dZ|%aHIhdE&3GY)9~e($Llnu( z;-Zsj{1AeD1b;!;5;UR$9pSa@>ltxHIItq~mT_sel!%D<&?~BFeGV((Kz$LnT2Uo= z?iA$$ELxb3HDEL1(7iWzVER0Gl#oulQxZpJFa0szL_WNOcN5$up;o{Un;g^kJ;GVE z58?QBp$QWzze7V+^5{Gr1P}ygh-UNP1#yTXzMHSn#pHl=Ed+{u?M_e363r3B`|W+JfzjM-Ht zx?L|OM8IR7h@T-s2K3C!7=R1lMj<6nA)e^>82Z`!1eX(})pv8e0l z7ro(*@ha&B>TQZGQ?^v|qXZ=iMF4vC%y0zH6;}t_gLy*!I@vHve$N8al$%0{cIzb8 z((c!ZxWWcnHtbSDyBuvr49z@8^XZ zK9YYf;F%-qT{iSCYu(Gcgl(OZ+4`5Qf4K(#@&*f%RO~4gkvtVEX;6GL*L_4hu7GPU z2u*afi;dS<+ng^R87R|R)iHz%W+@>4S?4d;*B?&LhG)*_k5_zwb>pFS!|VfGHBt|< zL&r08K2eu$M11b9;2Iaw%4{sNVlCV)A<0AcwQ0GH)YLkl1yEjXzpx4niyTOLi7ZO{ z2+hKO-yX6XWeq0t+5d5Z>-ZDa?gQ9b#Ca&u_*;uVuMpGoHP}pVhTDL@hfe>9t%752C-cJC=tZs z{jfnS2fyM>F+rPySkmlWCWs}I-&=2NnQGSz@o)c9GHYU`AePkp*&r4h#8NegB}-Id z@^m1GWh3lvK8Pg~e_Im7QpgeoY{6I~2d``piw$C_F^DC_U^a-wD2OFRx6(l@O`DR& zK`fOz)`9KSG?v;R78}H}+aQ))_&vxVmV98%M^?!<**<*TynEe6*;<2GGOTPH#A02F zwD&CxVlnVL76-Ak!To4Gk7YcMn;52fK`dD?n;XQEe#i!~Y|foxH7(zDuGiaFeXk{D zGqwTPY!FMCAeI6wu|X^rPIeQ-k_|c;K`d>+9t%6-F0FVeTXJ)p7luKYY;;`F%~x36 z;P)t!>^@KFGDBp0H(8`P+_K`@F&w^YU`ptXn$h;Wd)+-er@*$3#9(&u{ z%_Q?1GPgU22}MiYaNH%DmFA%`1f_Rwc0?d{092Gd08d|fXT5>bd*1t65|$E`pQ!oR z{Ss^XbKdE>`-oOLEwS>6)0>PNczqqMf_dv_sTB1!)RXcTtM)i?aq$mY+TM99e%J1P zl9!H6?8T6*DcBDZ_1IS%4S+0Juim#}9N978$|dtG4BV+URfE!xszj1Q$dk^wQ(>Ek zb~TB(#6>l`>sU7MLyz7}?%$HlFb3Y!+_kNANqC=C+vgX8Ct#_&7u#$ym3y<5VTnF% zXhOdBIw0VumEUjvVmiJP;=M$^HGq^M0)W~V8ryWd0qY8!%a}4@TkJ9}PiZSsLb-*% zA|3SDHt_gC8ru$|Sy^XO!(v_X>AovYF$}0uIPfZ1k%(XFKq4#c0o3FVy&LCdq?dE{GZOJ3L|%{J$gFy#t6smA7f+=_`=uMT)uVR}l>Q)6wjjbG{J69r7$ zIS-v&3)Fvh+1}5$rTh7eu3hQ8&f1$rShX}d7U@{i9Y_qg-GnuT5MURG`vC%lYex$L zEk0PW-GIMB5U`8aa*J0oTWq&Xvwtj{fQ^GslV$DABj3NGP~91tFog{^ zNySY(!6IfeHkPJreB(x5cC_OM=sR-SO+feKg&j~T`~)r3&@nzGBp@V?aY-OVju*iL z!vLrgkA?ocUN51~Al(T;&w*QnV3I1^=9<0o4JKCeI2rjU9Ws}|!ISFqBE+92VG@Mh zv7F#2(c$z_pKUx(X2E(o#K2b|uR9Cw@Psxr``w>-(XgmX!_uT4j)_}_qk8;(GLzTB zf>=Um;s9yae9I>*Iqn8DD)%h(Amao@V;rrryk3dHUZ#MF}-VeG&dpEi+>I z3qHz(1vH4DA(0^c_<{j|4HqVH8v|DHajZ+3adOP2t#mVqOo7-$!Wq>IlqqubA4i6N zLvQW^qXSOzIYd-MD+O>LNKYQ5g)jzw#NuEG<&mMGexBQeu9q z-bZ3Oj#&YDT>bmiY8kycJ$-n17*b|(mwq&y1oKnm)KkJ)Cjj6p5b8Nd`EiwTZYrl3 z-zEpNp-dJ9wW+6BQZ^nIMuJs{c+&|f^m31-v;K&_N@8ge|5t+Ba9U;dy25D46i@Ns z$N?UH7nW=1uP?;1^>NY`LMcs_i$&z6VAM+Fkvot|At1)}l2Ym5Uh?&qG^3VZzm|PG z9q5ZSe1$=m;AJ5mm~(YjQ1De69q)r^73UF6*j-*3kXi)(=Z=gHNrAfSpQFJzYbU2P zs*6WbN4}6a%B!@TR8-K1Eh~4^iL@HX5F8>SqhwBI?&59@wc~8`siSP^Lyc3wQe5#u zS8y@>g+NpKvFGHuujvO_#zlA%TP%2z_>2b*9zSvZ=`WAcT^Q(UKUUUcwMi;iTenclg zq~B!kR0WFm@ z@-W(_1A9!edIoEX)P9vXvH>~mED%Dik$SYq?vzwc2zbObDDEzmIuWXqH0G?x*S)1R z6~0mmRdsK&fd~Us#4s&^Jz;gGXxUdUU%u#Ny39v(ocYdzv}tTQ)?5=BUmKgzhUN*u z!W=58a}>=)2GUS~ABO#s8WN4e1lapA#x#6<{W_j`i@Vi5^z!6P8H4gv=uJHTyJzs= zS3?^}cMh;3qHcnmU(28)K?bqkB%*YJVh{!E5EKzG#CX1%F)>tz_=NBJ!z>yD0(UQy ziv|b}Q27&|#kdIWp)opgm_l#Mp=fej8 z-){x@pplIbf-yZF=T6aCkWWl@V)BNhs&z?Q&Ya`Z3Dw(H84qPy1T4z8)DD&?#3qyO`a$>RJUd&={!KkzNHGt- zd-O&E5=#DnhT+s(fjxfUy{X|u@=Uc zwv)PBP2$R)q}!1tE59veX{&2VO6inZp_X=F#>8fv{@{jSA-rY+2W;~<_`+Y@DPd_j zb7Yz)Nql9wQFVJ2{G|odto0Rt896beo~a-+>fy&>i7L{vmA7Ei*P|yvb{vRUO3%d` ztkZ6K_?>fu90S5FuFGzExO$|&Hv{RC(nI;8i-3+rOX4!$y-JLJbq2amQ% z1K$q5vi&>ws^;TSo;3IK;7jq4E1Ql*CPf;)av#sL7Zl93hQrPb2Mo2zvlNO{t*S)k zpe+35OgLrJ6BNo&=C0wVXm%kQ8u3H??1JFklbn7;tt7>D@|&~mE)9yG7HZUZ*``sE zYD_bAb=VK36?iG-oq}UM6ys|{9k0>vdOX+Z<;Im@4lS%E+?gg6k52L&EC3$&+=;;` z9o&L_N z{i8R;{d9MA#GW0ozk|3xBmQO(cV@)j47dk^o?13bK`PTE)n3w!5yAzW0 zMVbcXH^SxX)oSM5`q6!wsaf%JS{gW3c|KuW<%f~-xe|-!jYs*iG?N<8O3$*&6Ucq@ zHMBdc%6WM`*&QF|^{NtA-UhQNn86}}=~o0({l&MLm*ziO0{D);N!X2k9??IWFqhaZ z`o1bFX$Gk0AX<>X78v0EEC#)*tRuF(bB+-^Q;AW6@XlTEb&^O;@du){(WDEOX|53q z0`G_)6Alu;9f=<{;ih!o#c!%|RwhOC{3RAgE^}|(8JK_@GFiG4J7=|YmntzFHoLqg7o950;dx!Zx$&pTC&KegbpJ%JV@;l1w2J@z=$(Ih;( zOFAn4zzuFHDL8$t^Eb9~DiWblQ@JEl@yY=qclf<24Tqv-U)&|<-ocAz?+}BiQx8zb zU!X=>1uu{fZru?7ko0x1i1X*<7WN5}C0uY9;!|>F>4D}kK;FbEgY`}`W6Bju=X{+T1`=0jVdOSBwZbC@7Wx%hg@9}Hu zdta+*dP$O*-fuh~wH4+z33GjF_+WK!3(z1>dt)lhsXtlmNON~ZIJUH~Ewi$fq>QJn z{ayMNUxXvj|0^(sROkH?`PTU*Q>?ki7EU96NtK}1FKNYoFEy-1j!J&X6h2tLWO>0Bo@$jVqpaMU`y~%a z+FIa=sHEwwU(yP5Gk!^n20QXgre*#>{gS)4aEttsDH&;{UoxAa4$m*Sd!E|Cs%e*g zN$I{k>y+G%cjAq=YLjb1n)Bu*Od(E8nIo;}Op@s3gRphV`Wb|~clo1(OcI+ZB#GA6 zd1>LH?F!fcQHs^FMVNXJCd0O{PR_CbAUx74r${M$C}{wwKF@;@$`-gd%9{q(+i9h` zF};15%DM%(kg3oQ)bH8e<+Jhnxs`s<4DLESC#YS3?bs;_5G-^hvTo7s_&weNnPXOo zTHyIm=6&bbt`dmKO|G9*W!*hCjke*(&{Nz@e<`H5j#CRD9n{^0m{Y9CEe34`gEH+C z>sl=j5yC^Qa>JBFkWGvT)z^AJV%q|*N)?O3`dh82?@rwxs*Y~~Smdbw19igg+|n+s zWsBG9t@O%fGTh<$Wp~bVtz6yh(orjBDh(o!TpP0!AjDVVU7_w_fm`#~><(alwF*=0 zhTJ7ygVQ@kh9l!-+=g$Ji?wJa@^wUFkDc#RGEoDCpii9q7qK&bvIUu&H6BY1Ogwe2 zaYev-N$fAt)Jzau78XO?&!1tlX^h*{aRI)Tcr9RNoeB13-<`;LfLx!axk!=Jeq=C# z;OMK8R;Ryk3zfVFz}=tx8Rk zKxTSn9l6SxLJhgLP+vUZf~=ba<8J6H&|X(aZvEsBvb*78n{&**U@76>(@#Q6{CCzG zu9ex_UZL=$u5jcRO;W)jg~fZUDc_SXb5oX3abO4}&gzjos1f^ntZl*kPTyKD1SIz| zGDsP}zWn9<^V{q3<-6A(-e0}D9$#Pn`r+;Q^(DU%;`6(!zg~X)bUA+g{@3%Xcc};Y z@0wfpa&I2wR1@x0h8D@iju}rFUOp)1a~I_K#s%==oxXT`bqQm=diTrwbOrA0!F`Oz zYp@#r{;S&gva=U1)WNQGXRyZqes;2aJVjiJPS+p+ zr{q$GQ=!QC``Ky6^|Hg|V^$l_;Pt1MFUencNq^6ty*T^n=a>I-_VVYSUOa#H;^${j z?)jfyJpbumoM%lCU>&X8&~g4H41!f&xuV}Y`g-b|{OgG`38r9hymHp7+mk=zH&32A z7s2u|^zZIh&hux_UpjAyMseQ0y?F8zetqjtJXmB+sl7thf#*vX0E_=JaQ=#ykpv6p z`S6)@gavx+r{3}Zh8iA&wKI1g9k4r`b;NFYMnH1B9}{m$Y`RG>U(S5ocB0_DO6ng% z75~ku2yRv`ly;%~@{v1oSvkjDkq#3~TdkI_PEQ{m9zaiEXNN&}cRHg5qtmxn7nkoo zU7kRP$s?Z^GmvSrHuO=)-8|xA7>c_$(94%H%*UsP0KYl!a zcYSsF$$9_Lxp@EX_0{#&`*-l^7w7!le>?y8>fP&s;{mCl8Slq3#QsAkeIz3~D4#l? zJWuKXU&TjDZ-QLCV{|P`*mfP;wr$(ClN~$Rv2EM7xntY5ZQJJla?bglSHHS@bgxxC zM%NlutL}NtX73+pMRT=`Gpi-+_B_nc14o;3qWl^> z6nlz&NquB=gVc2g*MMA}nVfEpuc=SAJoB*33dk$@e-&MtV1VsWTXR|oTP4E7tPsoZ zUkrq{nqa-Vp>m4h&Jxj8vafCQi1!8bfIGX->?jweEe*)9&7vj}Jnn0*p4_=o$u%;B zTL>6&wY&Zvu!D`_0?B$N`d+&_YvSeegm+0~Xn$@>Y{c}~^a&*EF7E(I zxuM-AYVJzWVH5M^*a2L zq}%(6HD!HXo-e?m)>mWcV0{bv`ex zUSM7Pja8w$A6l032Wg|JmFp2{5Lwvvo$3wYY6NO1;j!TGfErHN;kUOd->1(obRW5m zE}d--F@+Is4bER1K%A@xg2c-Nc}zA|Xf)S755Yx)&79MMX-^J;J-6vxqlR(Y#$+iZ zm2Qol`+BDnuWPX#D954}JH3KRfB%)6c7@?ytT>CyOjWm*4#U zixlKvwcipXba-Nv*|dp!f4vjl)R%z;0xCAr!nO_DVLm~_#rvvCFuC->B$h?B!M5-u z`@ntK24+zVyE+`}iQ0!nQJ`hg1`6PA1HoR4Gs1z|-ABAXPj5O!vJR1)^cI>x(5XXM6`3Sg^)lY>;P}pLE(t3- z@**DCJr18Tga)0O^28*z+NdORz>@e-ie5}zq;{`~5ueK>vNbNK%X6OrTIVx{hf5I8 zvlr9`=Wqvu_k0-C3h)oTc3{7sjz%~e3ew+G^`^v*VtD~Xb?SoZt090b?yyPkcL$h_ zT3~bZytI;i+p&Jb=nrb&{4e(UP(augwYqB?e`KHS$yA5z`rZ2Z70q19GPOniXeQFE zOT=g=Q;PS5k4ptR|03|2^PSqpGoF-pjWY0v-==Jo+eB52>fWdkDpq|+xPD6Pbhbk# z$LTe3+BO*Yb1MCy99Q9ZQu-a6Y037K`_ww6(L4k4-Fx)ysV(pcdl4xr!#L;>>E-^_ z$4t#gM6uK^Y6`p=wRJq`K3k0H0&CaqaYj-rY;W`5>j9--GE-@S;1JfnC$R9zvk z>FfzZXe0Hzw*81n39S)RW)&eR4rB?Mj*{Sy%5S-6Zn)m)3|8chYmg4wtzyf+JiV;u zK`D7Ek9{DV@$snr?g&64rTV`=Z>YSVi;ow#QZNb$W`#Kk^# z)^gB!Y;&|rTxI$d3AuW*+muClVQ0r@u!38dpAT|k8_UiUu#$%xpw^_h(&lP+brc~+E`}81mY;BXVLcr_s}=!@l$cka zt+V1(PErtMsUJO)pIJuBs898Si@7fA@Nh9+gBq)L1nhCtZ`iL&bL#y=TQj(R1$*ra zez6uyC+*CYr6{a8#VqNbX5yc&69>(u)~s`7cU3mC?AR_NI4_t+nrpV1);Yw}m&ojR z+^x5y(egV^d&;gE0|lVOk?Lomf*x$3xsLj+jR5dmzG1wug15Sg5jl>u%5sNY2Zq{z z>Nt?>{tH;&Y%>+Q^g?%1P~9^1^vciV6hqIdP79m{we}-zEc^Ub`rtK}{M6+lV{j>5 z2m&Di!AeCp5^6k^$jdH7n29eRA=QRm`zsU!Mk4aXH zXpFlPDG!^tpdoC}jcRmuR|Y^SB^I+Y%BU%fRps%$2PKb&l+STK)kP7|>{-U6Rt+!f zBPeiSM5+oKAEuxuG)JzK3Uj=dX3H>= zLVBoosCp>9E9h8)O&?Gag|;QUQTX|4bIXa!&(Pe6QbzVNUIp+%drMgzbO^ zm9sy?J&8)UW&Y3)b0q(ev^on~hHoJWPVK-2fitiwh+lDgjO!tY7rhnoWQwMhNG;)P zsN;V#)xI)`VX|s~u@OV)A40qkA|BZ2hNEwu@IKF_KT)zV67bNb(4dgD#eUyLjX8=g zl_UvVh*VO+D=V&}g&^6ERbE120aIoSegUsP3FPJUK@e102Q|9gUURX~rE+&toz-|7 z+&Qp_u1?kxS^=mGtfF%KrwnXJwY=mCRvAzP=?j#6cC7m^YnEq0q_eKbz|W@edZ=fJ{r?S#@*8<_dCEJHWHYKdI|0U9ev4RAviGC89rA~`4%jghhtuii=7#}i3R%pMT z5@p(<1~mW(DU7Z57>q+%{cLGp2VWaVbR;0Ta^n&k z+rqNzLvLXj$T)j20SilHGigIs#D@F>EsHYol3Ui3_aVV}jr2BNw$fas4ED~As&&c> zB9+7)){6`bMZj)^17woF=o4&r?0ga6aHR&UOGC}_WC|sqsx>7snE1hc7&_unl^6=A zn99J$cS>x-<8yIN)=DhoQMZj`_iT9%4x(BkU;cppXSKc0uqXH#cP)MjupolAWJX-KXy$dqR2xZwy!OKSk8iI6@ z+Q3pubcn0d=y5FBa^iSzkg&dwm;71GrA!fC?|M$o?&(%Qbnqo;l#8;w#PCc8o5G%0 zfIZ{etpMu2|22?TZoQ7PKW3!4NsA%>3^{$zI{|EOom|qM+QYVnueiao3}}B4+%BNZ zBu{>u8g8>&qm4_LSPrJsrx(H{Y~Is;y<5Y?MdCxImwNjvMQ)CPE#vvmpT5Ygp{n%% z16oF2*?Kajd&nI3B-LO~d_ZE_R^J5dh5{`3yr$}wA`qaR*HgQPE!zI%5xN|kxJNrO ziKahuReB@bm{2ZEG!GP$4lOmLDM+$)fN`TLenFI^KklAi$0&DFyL|6J@~o{}DB1R2 zQPGvmc+nc;izK(Sv`aK53yCWrRpv#2qlVal!|B2mmy<%7(WA&DRr(_U0wxkor%_*cnX4in8EZr)oL#K`>_{%RSLNjWpjcsg2k z`-3+-YEWyKI5HeDTr;m+-rpRJv1K!O8dFkYxM}u*100GFXXw+eIv%Y)ZlKWEkd=A1 zd|b0d;7i-aA*opary7mwPMuvK1$`H$$qHOur*Fl{+QGsFaWfd+1Kq{Vp0%&j39F@r zN$1>&fN_u(a&qhKr_TI!7=K}J(2myfy~XuN;ZW~5z&o_M*8EEVCCUi4H#4L^i7%sy z^(Y-%yQ#CtYN$k8+#&azQ-1!E*he&^*Ln2U+WsC*;8BLInE2}M)Wr;!>1M$Qp^?p> z89~0UCr$^;Y+#>@P$o!CX3vVjWj8XclIA|HLXt0V(LwTwWn#9e5icZ|+l+S6VDY11 z`h}SU+rX6=9>N!0Nm}lRCQawLC}$FBnXEC+5Dw`RhHDC))d681c9W=3UK55cj+N4T zyE8kfWT^-x8__T$P zWl=*vDwD==@*Gghe`w{o0r@OB_{0VA6nVU_8=-t z-IqCZauDroMO9JKOsxt6>+$zi$cq86+z3#W>?%;~MR zf;x3N=uxC0;79gkMC~f^YgaT(;TV6W+!PLT_seXv24i9PJY%$0WsS=@(_S_}b%}NV zVs=8{LZYCl;TaL&hmbU4iVihbuCW@qUbHfKv1(nV*iYg2=Wqwelz5~Ai&!#aCBl7* za@DRQpt3lsDq3~+`cY$L0J3P>uFt_w3l~bj@SwWXrf`^|j1O$gm?C(|C-?U3&`|K= zgVNDIrGsdEeEp2RY9dfw)<~8yn*078S92LEc%@u+79%zP5ix|yAz?%{Z=d2vHFOU z`26$awSd}{qs`C<6R6alBx>}xPt*xvUWbqNX5MFL@_|i4<}a>7Fww^L{1gK(6F0iA zt?e)9u4d=6V@|)_(t+*nsoVr>xFI?7LM_dV%RYs0 z_d$r9d=4!2h6A14V6cYp#A^$VQHVEzd;l~eLT2Dd_Z#6Ec0quMGzqlaU3A3a)A=1< zWCEToR((WYPe??gloJW@Tcu!vk6}rtI|rlpF%5j%O~CAsbNpR&zY_i43NS9v^8*8; zq8G;JSJE#Q41<$kXO{ZiV9*cwDharY^5HO?EFR#-b$-zEIMxjW?*o!|&rvcoDF42% z%L3`$Pou!~mPbp2@p{OVHn%qOo1Zde)cDAEM5oS;^;UwXKRxgu5|M)K^XPo*=ygiG z_JB?=c7~pgj^7(guhZA{>+VYn68*JfHqcyKL=q&ED_=V*_*N1j$?Rx*^7E9hE@U~f z9DN!ue$FVy5y0Xa7y*Rs$!kqOOp?72U^r$}W?rAr4LzP>vY~Yse(b6!#RKJOjfYMEPU>MCr29Tjt1uDX@3-2T}eedl9vn+~404f+CI;%Hh_G6yZ)7wt(6U=as|NoggAaDn zD{aD}V8WmCMFg@SRBs5?nD@t;pli>(DCP5{d{|y$C}ChNE+&Orvm z^-^L1d#Hez3EM?AG!cymQxs~Pa?5jB29qUWtb>VZUqE;UzR@831nU9O+}T$`5H0ZU z02NXRVN&+~%(NBeeNH=lz$4m&`N{j(u&mh+&;KEn*##6g+^$hT0iu-C0$6+L3@85~ zmB)WbYaVpHJG|yko zI|}t)1&c%5NV`N{0gw9Lq(M&_{dE4e345^NFp8`%_|pxoc?v)(xOn1-_29F^^ynhe z3>6Uao11Ri0aFF*M6LrSQta{VDun(zwaF4ze+$9IdP#=ZS}uly!t5tO@0dkW{IcAC zkJ|^YQ`j9wJxdcVb=T+Xx3D%J+?;jaLB@`AV z^h}elc^evqYG|xd_kuQn{)Lp6=_e824+i4kwxXfR(@8?4%Z3vTAe0UXvhl@gkZr-B{BmGW!BR1$kZB#_B*J`YoV|so`b%hVz2cUQ zr{jJ-(>>((uacrN-j02o#pY6`iw;(VqJ_~jBTP)3bq{j87-R+NTv*$s@T0RP==3~& zc!X785LFDW5^*txe!M(`hfr{)T|3uMaHwOx-`|+<#{Dt89QyEZRxWk|dla5_y{Ef= zLQV7F;2BM;QSfjor)uCtI;yjc;NX{ifX^1!y8>|2c!z!dJRnn{3S-_&Yy?}4jyk~$ zvhZ+bvc^B3_n5V~&r82b8XIe?cPVzcvEc@g*K!`9qxaH^)oI(?I45TF+KBQUJb68r z<*J?iS%Y|7YyqQxW*5tRotn2<7{6O4qcNh?NVhFP}m{QW2XlV0sf_LFxkx${PH&|n%>41`Hv=D6bZ?@)p<`Pc4 zq(jM7348Gizs}&xREd%go&3wfzSTB+d%>Z6%{6xZ1N)htQ8)YU zZ(FVY!CzV?W1@lPgvJ{@F`9rPIH)51eFb=^MswWtbeXF^5))3_6j4N%#FHzhPRYB^RM1kQ7)vUQlVtH?;8mRV{PiLmmDolk|R zmg6r4o60Bz4%B>Z6qfReID=?8Oc%7u-Bce+OGTGU?)+*8q$v0`0k+#f#**Jcj%?vQ z(z$}82m#9-(vCbPnh<6~(`YXAO7Aa#J(H{J2`9Rn&IDv?pt7EWy?BiJHODa+hr5@8c#NaMvtAI% zJigYz^RnD4svKL7VgAdf&EhbXz7D10FwF;pG;p&!UGxujTWKIF=l3RR?D7x&OHUA4 z*wxj1h677eZYo|eTYgtXbe-2c+cx!uiS^K~@VXz^Ez>x$SUpBhaZlPmHNXorT#Kmm z@&34|)u%1taMAcq+_gYhE!&0ll7JE$VT2B<4J1%#wpC3uXLa#7F5L3VSflb(6X$|Q za&ib>Wld{@c0_nAO~CVRTf`H!`Y||;(au8k4(x~WWWZBTkSA-ww<&=^usC!Y7A!@O zwTui7vP4?cgjM17*y}4ck4z`C*v3I}`8z6PdO!)h>qW4ZK}8(O2*Uf)?bVJh(Qh11 zQckg!c!6QGR7`Klud*sm&R~|+K485Cz2ax#&CGD5+Y%`$+(o7{$Wbj|Uh|NjfUpnw zaQ)eCG7|pTG!>v@ReW#LSDGh-0>=<;i|VU{i_9;I&4JigjaOXik*n4C2W6Y&iYJF- z++rV2mv34B01hPbAPd18#*uS7)TnU8(Oe!W`9Z`5+%Nxy8)_$xlxeJ?AhB~ayl{-K z?-4&FLy>RXTgBK_J^!r9Zvs?!P@t%Jl`*#v#jJ!+#zF;|XT+OG3=pKM-}+85I5;zN zOluj)=Ym?%s3a42{KYgBwWYzb0zC}8srN#OYvMN;KclCoxSFTdRknx5Rkk2)Mb`#r ziY&NoS=T{{L@y2SyAY`h56MyD2x1{*vS4BSDhxo4@4IvXlYa4cFcY&02^VOddJmMP zkQZcxISlkDIFoJrPoCd25dpq^yrG)sTT0)@PciN=(3AN=%wh4*5}+EmRSUTq_#)?P z0+&Fq*g&m>_DoSBWTHhQq37trK2l&DlJiVzjl-`nHOYQhbi=6{0QVF^rK9AApWX)0 zKGwyu-g-<3_M5)M{?WiAdMJgV@%1N~xepb>TCW&Hq;stPG^D5IeT8RvYqIo{8_cqogg;_gBpTp)8yxy%=ypf&+}s6Z6A8LRH=$_%c+S3*q+!q& zOY|WVgdoSUN0YYjS81s$fZavr9!Xm6yrcj1e5_nJ@%`bn)-K~30Z;x_F5ODQ+S%IL z41I1wPM>h=kf+1*<(vF(`kbEEw>B|sB(`2g9Mp4u;jir3SlaVLR?J}j5<$reYt6@G zxvR(F1BWT*?)dcZ>D-R0cC(eOZd;9t}+ z_D41Tm%P*_=~^(dh#IS=yY-l@QotfIQ82P|&Qlv+!#~c%HJ$d#PRf~d7q%yltUB{5 zE6s|jdCl-kV@FNQqedi2HLiTsz?5oxwu*Z1bAfAANK$J&>dcXdu8awzWY9|R^g$|Q zrUyo4hlpkx{l; zTa0)>kkAa|N>=KT=}jYA$l5cHCKE`5^U<&1pCK=ehCHg>5Ai)A@kN?GhVASZ;R>et ztstZrt*t1oT~3Y7?r-H3IcjA0D`5Q=zzX(W(9CvfThv+|jva=}zX6v)Ly1Y)@A9rw z!{HTk!+-GypOr1PwMrn3LM&#!k)~==6=>wz$Y0N#;pMKs)>J4^qPriJck0Mt55Aa- zo1eZXaM)Aunl;<Cq!oL z+#2Bci&wZd8hR93pbw9%wl&Tl8XLP+LmYY?fC!EM{-q55IZvTF{_r#;fL~4AU zn0AxjiNdp>+y}QP1pIYgoP(*Y@#*>i=OkZO277xGc_LBLEg=y086<$$Um?8I zD4_AP-9K8P?ri})y|%Su0bCR&ZU7_-(P4Kaho_bto{if*ZlBWgzW4M{@F$HYkH=!& zkD1F;wpa%TGFq~?@b5*d6>W*&ZDF2qmJ@y6_m58g_^- zS9i>A+nLAFA-bYLS{(EetLD6cjdpGc;X&Y7=Q~Wqx{CBS5azPcw8MF}B&9a{Y3?}< z&4lx&UT4&uSF)A)Y_H+y?b@O#G&=+r#sv<$`cBvc9!dgiiCv+mzOM>jLhhP#Q%tS@j=IO(W)t=0~O*1j;V4e zzWd2TUi#SI7MSnG_OPel*BK9p!Vkg|qPJi$roO)gP>CkPEC$Am;6Nc3rqL2`J^S$1 zd@Th%Z)}|Tw*;0r-YHTMyJ=d} zedj$pPWU}KzR)7Il_88nx%odwbO9v|t zbA2H-T7G5B98}O^OhT(#eq?A84lf$;Yz|$j6IoF2?XZfMly@l->a`Wi^}GF=M2lk* zCg8ZzT{IUc#r&LmCu=~Kg)>vFv$GhpCIF)cTNcf0fFsGSsCKSKVoglDUb(m3vjdHk$a*IAGeY&=65LB&TVQ61a94?cUJogAO!t`q&K`J?48xF-DA)gI zK8J?ON$M`v(hYU%+26g9dYkAwfBV-xMX{jBno?5m>a~2_|Yb zJ`k8olZ@L{h}W#WF2FeayEI7<^tq{4{1l!1R!P@P_~VrIU<&2*e)Qa-VuF>vV#1Na z)Y;uryy5N@*4cd%ExgX8Os{f2CiKw%&>h4|$b8n8Bo5f`GWR=y0zrM)H=jp#EnE)x zbgib}15qy^18ZRa-hVQiP9&&vjRG%-4xp-n-iI`ezqeKLzOO6YotSfRi3+3wfeR>K zjnJw90VItDwrsFijth>lTpar{w34=(4}wz>+4~1%3oc6|QLram{)7@R!z9wt<&5lY z1Dws=lpct-#4|L0F~l07ElJh0au$xXHS#8=vr(tc1ZAH`jZ-zfo1kK@n5<;7y!m-B zzC%mVdCEClzR>-)HW-zFIiD1o$k{*`UidUw=mWmsZ>5;XcEq%49+LYJnc^ea30BBG z=8e;~NJ(zfUlvVKy4g9~fXh|3A&L4vQu3JX()?VccoT`-w*KI@fww`;zU|sGrlr4s z^Y?g3d4R$1E#HoTho@aiqx|frmigG=ZuDDuL!78 z%lV`F>ss^0rs&3B(nYFWcb-i0X8xt=tfQ=} zH!v4AOV~5FRW=-hF+n!OBppl$SL4D}D^#ntXR5sKIu}?+1EsenqRE7a?8=Z1N`|ci zPY0t0=Xsb@z7KAO5oW*C5|4LUc>IM`u}aocU;WE7vst}0xW)WtQ`VBVaap+Ijdy*0 zNKp5ku?lWdmal}zKsh#jH0M<%vZlXk4qx-W`7-<9=KC0<;=|{X2cULshz5+s5&d}@ z@L;!&2pIv6)n7d_C1R`XMKj)Lfz)EcVPr9$8fJv@gF)jR!x@$MXZ=E6Jw;`m#sDnq zcgZ|BX=_u2iF0pTA6H;;v<83G6*`_zLdHy?aQ8>5puug8hw2v4?=Ymtw774-Yf+M?Ybs0mp?A{)0>nJ0rL9 zhMXO(8zdQwKkBm^4b;Swe|(rjrs!N?$keq4jkpQ-RVt{F{K?qrH^ov?QP2@-1DrVk zvnO|&*t$EhJZ{Lkd0<2P(hQ@vM^E!Q74ue~&XS6TxiN+Tx1NCnz2dHP=Nm zw#ao48%bq(W2C4SmhK zOR#Rd&4Mww+O-rw3x?NK$lqLSQN(dVgTgVztpN#U?@c0UABr%#P86*v_l|;q+PFsb z1wHr9+f4JEw!X3;`YP~w=|6Vx08JBq{h|a=9+pb2M?^8c;Sihe?kv^2cj0aw{n)=eh$T|#v0Awag3#(q8?E!^u#MnlXfrj1J!{*Xy&G>WsMn@EjkZB=ocYy zuT@ZdGy@ei9g(IJVSgEy2Rpt&QRs$_D8|urHy}6z-Dp1^wt+Em6k8-igjJB@8$_X5 z14N-1tZ@>Uma%a zALV*`=Ib{*ffKxdwj%16u=F?<#V|)?WB>OaP282eN`U=ASv|HViK1NKm)s%4A&;WjgD~0%#C(?r3kQ7wxx&p96kfp2V|J_? zr9VGa8*Nl?FSB$g9+W^Q!fYM!GBv_-M0j6KlnL|N=SPmAcSxKV?NF~Mmnq75wmLq{ zg*n7^Ch?1F-yEE**nU%asoPn9MmMsA4QzZ^pzfC=qk<@aS6sY8@N7nGRRVZ-GK7{i zJa=?Mrl^F;`YM~;I2R6fY>GuMwFVB)64FW0ll1aw>gH_HRAl+M;PK`t)s-V#_jr>1 z5IHx3wql2P?INDs_#Z3C;WdfM`grxBGJ}IU8oNcLOjRIVCc|dU046m3q)}SlFdVl} zwTl#)N-%wWUDeG+V?KljE?N_&L(OQUCX zEnUMU313_HKk7=HYs7RZM=4A!u|)kdT%73&4&icu)B9rAWo(YFpW-*EqG&CWQ8aeP zm0_{x^arOazCEqDbfs6lLI1U5PGzAggYAJf%AC3|@z_V%ddwi;IKLTXm?RJR%eCR& z)N@Ff6Nlk|aDA;YzXXVpUh);Qy^?m9t>{XFJQT?SPkNv7Wv!nP4?RtHm%JP5j~ zwEXLuxPj7f8x)#;4rsh~a0}W@NK-rt80eR##^*78$pJTEr@XNQFHsyxr^N$H(v=%< z4vKn$y;gths`MkzteS}SGddq1eB}t+=Lr0~T}HHw>6dhL&{Kb@=NU&lLx|MeW`({e zP;>c5?5ix8LL&cTNI1BiNCv^VFCvL+{e#;n>9Ylw9Uc&ZuDO5s?-;fJs?HjATp9;A z83kZ~QyX`I6fET@0M2DkK?9iH(oMdiu8({ zfpdynwMqp&jBZ&cuIf*TvJkdZ5N1uaKwMb1&i%6$_ExMzVhSnJvDck}MH>i-L zW^6a{@@e)*a+gTS* zaTNUL-inWmu%dtL`m%M2WJfc2VJ9jySkPp!YPc$Gu;!1E6~j~9{MzE}I?kj;0&5<@ zbQ5dR&QrBUa@W!O%vVYqmuQPG?GvuDcg*{1%`?HxVr&ZYi@i)_c<$p+ml@LgVJl*i z9G@99G#^~TwUyKJ!hN=z&L(Li(RFy0rWMDx;4$zCL((`PkdPoh`iX ze|22M-t3$+^GS|DS~c2VRB|9wP(z3`D>MtL+*jwx@EsFNmc#m87bT$$ifK`95h$!< z;cT&RSOs~I=T{QAZ3(S`#a~wW*GHMTW3G1MSKJ{*#Qy4Ihu@WWBl5nG07F=f`;Y?? z)Me=w_5YLqR^<<1Ih9mzdYK*;)Awu79x~DZJ3HG9HjcDUu1b)Jeb725sJhVSocby- z(bJa=^#DU$@4fuSA@TD5H<;Mq0a#(KuMZ{su<&l{*+K5z51h(a zt8{75QyuR4%_%^Ay#x=6=hwOc9HoQon%EGncDmsjs|S6<$KGAi;OSOd)sSY4wnj^y z!R@u$)qD}g#N1ZN#98eAFnXhdc^qjXD;`_C5ZT{#A=wqNY6h}?x{P%ffokAAo}znz z&3<2BWAh1sD^k)1d8#AcAI+k&4JlCOdSb7XsMWaN(TlVgN57ToJ7!a%0H=4N@xvWEdUb_)s& zFu*Kx4T4=85o?4xV^v`^JXD;C2y|)+DEZvm`VN#o0C*)U_OFv9pbYrfF-0s$92y!0 z^%loH4z1s_QT&pORfuzvruYArk|=Vf;TlaCp$^OTv3EbqxAC*jkfq!hWP)C+*x=nf z4RgKg>s0*`YvaYs2KS8N5OEXq62kM0k;9@ zzV-d3Vu{Ja+2j58mZ3;ypYF?y1M;|Z)W0;yNG_#z9rP|MuoLeW=5P1#0Z;g&NI1pz z2s-Yh?v=F+bqqy5CQFCuUUoWG}qO_powtlN7()c1$9;U!PKePx_G2 zUH;RQ+zq19O-!n*qs_$`ic|XwT?0%zA17B9sl4l|{i7)X#;S6H&5_udi-7kI&OfRz zwsWWcJzI&bT{9o&j4wjn-?Tqe1#EI8Xo0An?n%!zIBS7bfg{?l!PW-S!L>o|e8}8W z*eUhkE6UrJ%Vfu%Eg|Li@4RLAUU$|Ent@`O%e_uSoLzKf02F*nf2;MX(|@zEYPl zQAcv?ya)^hWg$s87R`h)6XRr#FSnVOON0~N)|u1ijNxaP7{}#bWcJ1i$uba4V(0UO zTGC3KgqdV?TXvSCuNk*AkcO5oUOF0@4ZGCE0III!*kKF;qMh>zOUNl45o%sf_eaph z;059-G0eWv*=&lkBN>+C`<6zI%d=So7^%Xf&M^h)qXJk^AWl0*kEE<584xJDmm?ha zXm{^+JP&BD6`rR@W9dv_N9D7bZr`pmyL~kwY|`u6_T6d3CXynb8L=KB`$OMxD#ggg zHx%ljc^vu$BM(ba;i>aa%fC5ii{+pI=e6p$W-HBKy>853-E`on{ zz|vH)>X}kE{#0I!Xjvde*PsD`eD5g%Xy*_^P<|Nf9YRo5q(RP_3NhP}Wd1@3vJ%dT zCo|#+z_~9^iGJ1YQ)-nS@GKHxvlq+QQNXd;9Ah6sL;Eq7K>uef@p-^w3?uH4Gub1I z-q@5G$@tQ$&yQt!LMLt$E(cE`97_xM!Vb@7Wq$!B4MzN1R(J{}AaPqgEQETBB{FnJ zgn`Uns_h-vcD`n8FA&EMXD)nmMqXbADx(heZOD55dxP3raW+w%(LE|7Em=i+TPOi8(E>kA=fD`Y-YG{y3F*w@lzs2v#) zB-(<>VD1un%x_s+C=;Hf;$Dp~tG?=J3O_RDi+4eCGBusp%ZE=sXFiXIUG5N`Tm1`g zmgSOdq$rU|{gApeOPHxJ93Tm^guybFSq!9+Q-Od8VWqppJ`QlE(o&*)ua>n3;o6R+M~ZtS}n=qoWG$yWk-6Y zosICw}!!){n+`ZPIYi1R237%2ZDPG5&isJB@vnkifU_XD3o{M)Y zGWbQ^=Qm3O=!YgMtwvGPq0C>$y?JKf6c|>pK$@^YFxV1)1EQ2GsB%sULcUI<+nE-T zQ$*xXvJS}4T?(-f?1#FU_3RQR;`|oT`SF-Iq&FRYcX8zPnoUhve6Z!}#jbb7wb~Tll4&n6EKCUk5Cl4UX^Jws)}$CRxRh zIkDKEKUx!5iyy7YInIyP#0}yft;vh;kJcopJ2s&O_}V+K)U!c5Q#iS(yg89C39V%es0CzwS{i56#xRa#~UHTTzD16ML zDZ{l^$C{IrmB?)ypajl+qK3Z{VYY3LZ%ffPd{Uwj^Xb5fnb zb5GlxGW;)!oVbHm%1&w=p#c2%{>G%V^em7SjPJ0CP*MQ|BB%N?4NWFgFy_m|;^^Mj z{AYEsBVkJi`!$RLU*r~LyNNxQVHPL+1g=$5AnKpg{T)e$T=2-d=pS{;8H)?~AsJZs z__!_9d?e1eRL(*`ug`cPBsvv;RMJezXUdA_(ZoE?Zvjl+zm)O_i^+!dGOLs|Ph#oR zHN?s4S8Qpr2F2v_@jjw7pnr0dvP7i;#OK%{iRWgB-%Ck0!g%vTK5i1D)fk(ZuysJwNxc*x(chtF`va!f%9>e*g2R(Ul_ zwV&02J*=YcjXFT{LN}+=UaA8`Ir{vjSXhMN^U`vcIVv6W!+jVQ5rreSW zAP34L3zUTT9tXq}g(2Mw*?@;z9J(0N=%h%A`xLG4l$ix86U^@NL;eOz9;9;fZ}7ed zc?~VP3~Y+wf2q9$p+ux>wS1%GJb4m8rXW}_NbdX5H3IPbwPUp_@H-Y3@@14f7FD8> zY6CckijYfS4=wU2Y&q{d(W7$Tev||c$9Rn-k;FEwtcVL|ctI*@%@ugWlV@ACBw5Q# zsvtC`1U`_sQ~`HK$}`HBe#87WEI2BDGx}q2OdFHL<1Lr~yh$n`4+rdSS`V5@l%+y?zREOMupbn1A z=~t~rEdyYrRWv^trmw*tZKruu)8i^yPzvnJxBd7#G|ZUT@=ybSK3dEZz3LkNtQ^>x ztQq{8SAz>|_+S)>QF)m*7W2A)5l8nRGsLmzORm{SWU8s6>_7E1JgkF8AYmDIn)NHV ziYt)R2l1_=dyr|Pf<>vLhK;eaG@mb5gdK{@yNWj>kYI$_wa0Q2d1xWVPot_dkS#DV zipk!duk*m|t!}kNFHISIsX?jcFJuXpT5r~gpUb6I@M;6i008$+EG1(zD3B;;!bqLi7?o$+UvXR$1ULz`{A530;w3`OTm zYTW!nvT~}&PEcZl>~8?qTGazdNvnOVY^oSfIF(=(`JB{y_o*T@S~5>Kr9^Fx2(iXL z_7(Di%CbyPBzVbQ&0UGIqM4uT#&4E+!qEU+4kcwG-}c;)Ty5LY+>w+G=cMEf+2C=5 z$n9UO8Us;h>3GBEt6Y|&)iWLU{;{w87R)$44wm}QzS1a@khdGiU^w0m8KmX)pM9kq z_s71nWrmm^Y_SX=5|La3n(QG!IuKB6BMF?2j%S`MUx-4Ir1J15^x(SG?~`ifDIzI0Xv+D}GbM>eQn7F&_% zPd=BL`8+cmqT@t!3eq|1$Y6rJ6S<1@sbQOQQd~W$t}Xh;8PKH$JJ-WSSz6#F?FVs7 zzJ*zhz2%ryD2B%;$O6sx9Pu)xE=r`E>5pR`$pLCO+3CEhUet_P3u%?R0kNEJtP(Ug zAQqV)CAX<4tt_LwCNC)S$7A|8-SI)%Y2e1f$_R)k27$`D;>y5t$T<_ zoqY~ME{B+U-l*?6&R@H-JqC3yrSCw|RkdXSE~1qbFYLoc7yQ0)2cSzEj~7+fMD& z;GTZ1D5;Z%0)kj1KOs#$NdS{~mOqf4@O-57j6QdiDQ| z8LK|1(p_>s1Jr!{F9KHdyJ-KXF4*nP_KyjV7u+&%&NHZsSyT!yj8K7BNiFzI#LYvH z!I0s^*NJL*UB4Kt@1}4VE0O2t8-=>v8v%!%hnJ-#lPCHExTX9s)$;eivo!}*>)r}y*rN&}qWbU?B)>F$h7;XXAyt;ErJ6i5Y_ z=?v_<+T2~ZGh!Do!)t^kaQry_GW$M!e`U6&9z4vh`eEeibwj{JtmSm9kEOx-(Dd>v z?IdaoPOPZeDs13PT%%_JFUj>x_}sg~h32Pf1?#0G>WSOiWBf91nxVq&teldZ$5f!V z-+rCAyFnA^zXj#f>PNpbEx4NiG5;|#O#^l8`WmhjVCOBD4_R0Eld2>K6Z&C_^3^4p zb_w9iqb(Z@x-EFbuhLvy%(q5{>sS2?zb0l(-x6u45FGpKk;(v0L$A1bsdcE>s>y&P zLPAITC!@0TGuGd0JS#eH>NoW6+loV>q623Yg*}O9tq`(QrkhdpX6tdY8&cwmKUwTlUZEE`zMPM5H`N+)f5> z%s$;-hwOHBcerPVW!?lzk|lXf)|RN%w?Zz!7>*XmqvcMxvGEmo_@{fQc7F_nkkEi`j zcEE1b+n)RhMoWkb6hp%0 z_r>spQMdLK<7rsBtncHF9)#f0W21dX)vLcnX;5-s92BfW0nut@^N&4!F3ip8Q#^S8 z0#IJY921ZN(IMKr2-Csq;*53_Ab6~duNYr`eS7n`rKLw#icipyE%o`k%-qvDmyT0X zKF-;v56I19y2JfS{aHnOqfgP;(+|a6jOx#Vte`dlB@H^EgP1edJVW8Z%IV|#e0f5U zFMREbP#o-6$rOkzMpBqG13$YK@BaT#UZCs;bfz&nenR|9dC7MB59LLjtl{4I#F)h| z8XgGkj1i%v4*kho+q@#3Jnv)3n=KerU2c`!wJxKl`$>>FJcrVTuy7R5ep@7^<-#7L zZ$DQtm-z!-&wE^oX|{SQqI(k`os>zM813Y^>{nu*m^bx%*p@3 zyug6)T#Z})bsPTsDTe#i*u8!)ZJdhihCeRAxnqXyG(c5V+7=oS#_Q;by@nbSF)5iG zj&<*8lj%V0=#GCrZP#4Z0>fqI@<%|)9WfhsBj;dK1<5(Wy>u}V;a=W5A ze2C1zo&wrVx%p9M`l+%}vSL+seMF`xOu>!|DKqXJ;MsJ5=5d2Y@O>H7572G8b7OmS z5J9x+zJx#IiHyemc`^so=G+b4XNpf<(rc6|3-5f^#|ucPhT z)$@LI{zD(Qx=p3++0zd@G5|5zONuqIWqn0&wOVpqFM#WWazR(L_u~e+)@#C|7;DC(qS866+4Z@od1XiA z@EuK3v7(S9Sp4FLO*Xd#k+kp`+dxt;T-KksDCM-%t<=<#$krRaUR)|xQeb)d&-sb< znW52Tyvk=&&*Z6OB8`h6f$#0Gr*d_E%@bR|8z)C zpPw>~K9t5|8A)h)LVnFX3$IhYKu1n##{`w2(e5a*9nv=4ON6ge%->lHHP#Tb{VX6;1of4cg!=^^s zcs$y5M2eA()c98stI;Egxo*LEQM{1&nRCM(*Yw8CR+ROYH2L3iX|^FbVop_U0Q*dW z=qLq~zTcx_mN=y>M;(7m*vP+>sDdwg(nlIaZefS=oDWw{8D4)(VO+8tg+hf(@~dh) ztYE+zYHtzbn&j@@)-4)s0b%cwB0~+~9{3*PcOc*bG@9cUF{!gN;4xj(<582qbhia% zeUqO*_;|chX!%#sLGqFJ7euYKKE9-`UW!QWyv~%z*0N=hk>bMLnr=sf&FAC!xx@%^ zh?HVs8axFLU^t)>5Z^8wv~9`12zf|oFb_jx!TRPfM8)>^K)vaB>7`|7;D%|$xLE?i z1jQ8?%|AtB`mq+w4<8WJ+~*R*2NdkCMbLBRg{JEqea!D+1kvzF%PqqngWi!0dE+~b z>A^<5kyS}OCs6q}jdTPE3c7!4MBAP%`Z#U{F;*W`rbp$Y5L^&u5=#B}NC!+w{){3i zK}4rd?C+6O4}=7U(erFTlq+V325HIhYZ>57cgp0d#t8c}X0VS=<07S=q2v%piBHFJ zq-=Tbz{0Q;i^X!-*NFrtyiR<9kM*pqkDW!+NMmGsT*L8LCdMCtvHE;EZ$n&z&>6OAsiJA_E<2a!}Mn@Z@c zuP{%ch5+OeMzUO3aV)xJNIsI)fsoOaK~s-&MIt>X6@HeT>3!;AXw!mZm9RI-XsOsa z$1;k(kX~c#6p2a$9+Mo;!UBXettqYPoD^r=whKuhaEgr@;o7K7k~kENz}S3d&B=op zl9%KUg)noU7tJCzNm$6voo`?prJu(WpqgWp(q$5~O|s@!K})-z@T8W^wuX?;UcJ3%0>{I;$%(*RS&4*{0xfAKD5asK7b zu9(2(j{RTaAj^W#am&JXS!qa*oi_>8f5g?J^ligyMub$F66klT>J4?7xKr^*z+i|< zKp3a|2~`=-MgFRPED|`o@OrnsnEvs6gUVGdxp^2O^YPh7PAnojI%Sm?O_dE%q=frD zc5udx1)eS^zLLm{aU__IA;lb~=Gc&oZcJ%_syeA?n2}FR#uY(vQQ$|1rY=pB_Nx#K zp-yw1Hd{B)3d*)B@$$1QsChiA8I-CMI9mPuy62a} zEyKfV6|(0aoDWC!E*OKN_R-un0kI|!@0eF~;g~yG%Gq)(I%|=y>32r4S?$VhyWhtK z1c1AQ(DDqW_r~_gw)l<|Ao8o{{wfa8veiG zE-ZlnxJzameEGQOveAfT^z`@i|N4g*m(AVyO|LzI%s$V-3}t1 zT9aB(ib#*vv>Sa-q&v^-A4?rK4)+o`bql4a!kWCU&N%&i@(B;W`OUM@SJ&1rDB&{L zQcAHFeEQVDypL)_1(Y_MIEE5Oo7%MKb1oaBj=WMJ_BSYHT2R8)f0rX#Va zJ_;~AlUao1fUPitsyo*vw2#@6UnCoBNl!?OyXwn;y-|M%zjZ5kC-eJj7WGygVu^Qq zRQX+oExrabE-Yq#Bq@WBJs(+L@>i@VN7ySwAtfcC#{g3mPcac{3|~rVeh?(fM{FOc z8M-mMjxBW(WlX4xFN#n}NZr+0z|qD{Swkvf8&yCE&h_42_04aZ9}WrJeHIJCt&dc3 zKPqJ4o`WdTiE2pKjW;O;_3U`ak@+#pofxef3$gBDOiH^8!aZ2xTQ`W_qb|r)&?SF) zS}|MWi`$+kFVT5lkdfGC#ubCkV#==kTwe7|j6p*8!qT#ia;ILUCt8Q&>C;g*nzeZ7MIu}Yw45*gMAn_}fjfMF2C zR?Byh<`8)u6xCkN3-R{2O6Fee0{>e5bAs61=C~S3>%i1JZ38?qG~p2s1$VY%6q5hDW&D zie$ijPU?T$*G`!jEIz9_cdg7a^w6;X!;xEA*YoQS<+?Fl-w&m#r zX2xOVA-r>CesyRIX2;oMG8N|IVZ#`i0yjUE5=K9Z>!Gh10r?>{$pc$NV#?@F#Ec~C zCXldc09W!bE)B3XGJZ(bww@<4BR!?yn)RnNGre6nhed;xOKIZgIjD8OyYb;U$c8+@AP*kwUInmWR8$Jg4vPDo;u3Eo9h!e&P#+oHRldyNnI9^+yGoX7Pp2jNfn8 zz7lYu$9WKqC!_2?4qT?LLosK&hPTggjjs-+owOy~DIZC5{%$k5-&U3n54T*6R*sUq z(llq!Y}@-r)j`Y+RB&ci$sy=?cs=-n(Um}L7G*ucHo+aT27GEgVaz?+% z)_5xh0WWKUKED0o|3^ZruSrh*X_5_=!2*FZIx^jnV^xyM$lqN+bUM zMn4FQVo)C)DeJaJ?vBY$E$mo%B*`KOBXWTzfWYz_{ZYQD9qo9g{xXX#g|840J)F#{ z)#`B;;Wi`=2_S3)s07Dm-KAZ&{P>V26<`;c3GSGw<<08y{@yPI7Qs1vhyeAPBD9sp zlE*133q+`TfG?ov_DP9N-J?8t4)gMJ#LKlOOEPc)T9x5;91n&835b_V$fO_#8z}1^ol%K z*uDSSQxxq8zDlOcL^}gx`R7k{PX^fPSpyR6GP-?NTuQXr>;mFII7p@ToGQqfZ7(N? z65RewMBR(rSR?b)Z*;qOoSptoD9)4e9bCgiqxT-MwuEN_>_4>3z&Ij159j6*!jz)Y z$HXexgh_PT~p@)KOCwy6E4g&e0uhA3iXNN*FMD%RPz#12DfT{A^!lq`y8D` zbO5zH&JG_j(JP!wWZIw;5&oDE4eVY~5ACgNU1znr9C<`hk6P=)W%}c5I0+lc_86q}WB0u>W#A;#=Yl-E zWWIr}fP`Zp`}JB>q{StMPdSnwb#9bXXtTMe3Lq+jr$+z&QTWwmKPYxT3&!oVL=juQ zV$#7yzr-PnFlQ!-SWXqQIHBrDxfFA+(;^xNjEBoTbGNy(?|^8xH>|r(!^uaZs=Ce& zz@CU55~Dgr@ng2-DXvz2h~?Wfs792gbi_gk@?3;hTW8tr90&mfsRgS`jg!~f`nGw2 z%jLqH4U0PFhOm4F^+bLQ>D8q>?2tDj-^@QCReSat3a8|1dTT*<6mx5B+=i2(V@PtDXBd5$!e z++#>n6Ct(U+@w198%jvtrS*s;Qblt)N!1q2h303BRslAg8rW50ukljnYKp2t2KhuZ zVxoCYs6(TO=8`%qSGg3E40(eqZvu!%ad-00%mDrwM_ji;Q!e-L5is@*C;nKEn4qaW zDWOQKDDPC4n^&YXpJUXU{0Z^kFXrx?YUlpmUYi`k80e(kwR5T@1o5g!Vu;*Ij^BO@}jixxWjUfk2M2g``3E; zukd{PW_xZ`*e^(;Gjexspcat@7Gk}B8Sh>Gh3;ARP`IF& z0|26cI|YC!X!|LCj4lecvUhHt{;Cz?IhSJu7O{FDN5KVt>Cs<*f#7(o>4k@)dChwb zd}r#otYf^Kt>UJ-ZEO}93SK!@5_msus={Q%C9G=Bd=%LSo~w~M63!3ffR3oLIAk?8+u(&YSfp=!17dV*d7n( zEeek5k4({sPf~&4liMjAH-G&Ltb}@^@hS&Nc=N0+4;bz`lwh)^uf-!zRxTc{kGCVG z1txb$H($A#96*rga`@pFAK$7uC*xoC&_cm&(~=D2`}*XxuDF8Nkt8CEE*Yw3#&sTA zaqq7qLsZ@#U|;oP(pP;7Gj3|0p22;&^TH{j4ANAe;O-j^F_J@-juA| zj-k2d0Qp8Bp-?;oGj@p|{T|J`_V3lESd%(zq)=jOuLOu)R=eulq=hzB=X&V;HmUDzmuJ1!z=W@r|mQ>&gvt|Qo7iIlkMFeFMc=1GXh zt$w@H2z=`3?`-L(Zyb`~aJkRN!3@ELi!HuQK0SpkHtwZAyd9wGNpHDBzN2#t zvw%Ofb2hyQ;Z_V7DI={i=&-5T2Q=(B?v~b2FKs6%SZtEpI~4RiyzH{rK@) zTg)@UTH^myl4eunP=s4p{B*S^m5V3MDC?&T3MPZ6-C{oH z$-Fiuk3t7~)6?A?TNV!k2a(oZWir`hXtEWWWP<6CVy^nPB=3HVJV?5{`OG2I%H^e9 z<9y6m^o+`jQ3D)BLxbXrL8_KeE}{kXs>)_7qlV%Diq3Ky@rR9VlOY3JLkV~`e`v+X zqk*aHMbv`z(1MLg4s&IJ2M?E2u4%Iq*i{z;;%2b*F@BvGbk}=8I@=B;(1#ZVlsJHM3(8ZL^=9s#zO-hgrDV1>3L3YZIKRHJMRol!|2D+=Z$)3vc#f z!B$R0{_6c=o)p8_VrCC&5(q}XDu%)hk1jS_0}IH zQelb`ob_b6w8P(D1bB4y3B6ZBB%NUqL1N+7=H{E9t4m>?f_$g zsPfV7=H31A+wHH zOVq^(14OjC6f?4KS;7~ZUR6XlG)46RcQC)^`k;o>j-}7VK-H<{pPlju?xqF^vfm^N zV~7z zJXpHXA@jFl@Js`P2MCyketR+q80b>IFfeqi!+;nbH~m>0WnQB{E|joa{y@KM_IT~EGTz=7tTXjfv1RByBt@Ifn&AVuE~8~Dmp6*t zFE#^FU(u?yT!P)=TL>J2+mhZiE5o>HC?BD)?fZWI3MV#9`y|5~p^#3|Ym$%Se@+;Z zFKR%2R^z4D4$+Y?>o@20CkXE&unMeZ zGMa;2pUTz&qo76Zv5rBe0^&tock$8b+inPcmJ^#!-ekk=$};4VeINChblY5ZUC=!q zFmd>AFwyjPZfD_J(%*L7ZgMvV^OL?<32(cgA@Lji2(LDxqIe#f7LIsV%8`+=OTioV zdRW(5f{KQk{v#phqCW3zV3dSFCV(&{kne*-e|lV3V%;twD}z3&kgEZ8VvsRw=-LRP zS`2|~eIgtID>Q-Ze6=&E!y;>m1CT>;j0^r0O>`Ek_gW|d8wPI{ObY}CPZmPq8#^V( z{zh0yrdw@iT8F@4-A+SGz~D-CTcY=o);$lJ7)fhCm`C1@SRlDeJ3d>z^uvBmV;mdX zCC67>wCBu`{9QVM%V8d4qBiG;f0Ih9zT&YymcEtWK|#8d!hu2+E|!izR2Vjc-unIHdOEpHTg6O1li&E|4Xo^en z%klCvlknDo7%u9U3YJqGyjp)+n)~N?;Uh6N1K2zuLdlZ-U7v)S+e=i@zso&v`oagE zghF(G;~(oa^bHMaf(BmhNgk)4R3bIP6m^_*8Vg914#c|a4Y9|V^MDLG9`1(6q>STc z$|GnRRpDzG|D`Y?3h1V`K6!gn`$0w56yfvedPn-3+1Z$-X?afLNfXY7#W^z+@Lu3p znEk{K-Um^E&N4S#S^0|5;!#F*lM@*r~ zyCCTdI^p0RjT+qGI&~Uy*d8S2ynXB<{{=I2ED3gpyk~qEDN)%Y&e*Q@V+1oyc zs~`JMBTEjX{oh6wf0H>A$W{?diEjMF{^7JuDIs`|Et>L8CJ<`2U9UQ2zH)Jq3#j2~ z+8$|2?u>!k?M$q6$j;sIgyz=S5-XOi0)b>agIzoLXsWO<3=^I$m%J0!|5T^&i=i)D%Rf8tLo~EE4qvT47Ic2 z5#)hK?x}nZlHGsZ_SWot{^iy4{j|%5mmmvV2oSiCV>}I7UwmB+MOH7zm|=GmN#HYQ z#Hj#7Z6TXI6%qJoi+Pd2;SkKP7Ec0K3=rjhL?8_m$d!Wnjjl|1Un*l^qNIrd-J{QP z0#2{cb6;A>>$f_gtg4di{-9Ci{BBGJRdt^>;LiY?7Q_&aTVXvznb}z3I71nqXx%|s z=&V9GE@@U_IS0uqtEkc?#!k8UzmwEl?nHDO|NOE(>f zG{w&2NA5;e<_6D5($Us9POXo0j}oSg^#(1~9gA_Uep_68W~G(tDlef>=qsMSXw6F1 zjU$T{mZF`6Bh}A}oa~-9bxzY0@@89}8T+DZ-V3SB1kW?86Q;asz4RP7%{di2#zqkt zw1QL_#T2qC5!0DGodTVmP@btOv#S-OO;&oX^rexc_Wppx zCIKsiEcMt59{Ys`5Hc>;Fip9#r(jif`vQjh2ly;=6s_w3SS^oh;aZ@VZ>7vPPuqnOjM)BDo7;U zP;0C$rGxx-R*iXGuf+&z6@ox%vWku{A=l`UZ<{9Jvlx~^| zlN#S!qMX|*Gs_O1f%|c{_*?_n&rUU5x0Y$A_GuIayuhD&D(l#8ebniuE_q8h=A%$W zsUsV57t+%3BQ0!Mjm%z&r?^%Sm}fT2j%)Wb>vrBlcMGbG<>?^VP0$Z;U<^lJe}Va{ z`gRhZ^-ywi32~B%!<+mxNe4B27=$oWTmlgUdC z5A~B2({+h`M^h3r>E^8Kn8fu2ldQ(=j$@8fqO7{>m%fB7==|}^FgrkD}zS7yppzK&w0jAwk`-%Y><+w)*4vx)?ekUbncn=fj0{n zmS1@*2%4-!ZI&Y^!*!LG)NKAd6xM~SPl_aHwhrD_JUya~hkv#=B{y1uRvgm|K-Q|A z?I_0GN@2@=gn+Zl@bqE5xKu5wXV0_4E6xV$OahW=U`R6m=v1Wc)pnq1R>P>vaKcbQv6|TbSVTfj2 zH=WbV)pxCOpVeQjoAK*(AOJWo@$)Ywi_gYQPMz(Qc}gm*JzJtJI555vA&cgpUq+-! zXne)LZS!>a(+hs!J*{Ud2WZecloRgVXkrxUEq9pn%IcM#x*}ENj#ekLw-B$|jglpKqe#Lhi4hj;-hB^AWEpdqYDN}K^`PRntUt;0BJ$tUwMFf;pUG& zKx(9U#)%;@&NJfClCU{e@;epgxFB(|vFF6K{JDYxyTEDgxUT*Ogd)0bP19n)>O5qa~PkdJW&f!^Rb>R!zpux>Sz)7V#`O#2=9=vy@+ zr9Kz)PmW$W>ON$IuY8_SyVsn(rxL4_g1{~)q2B|FsNMT=<-&P zqM}Ep8f7Bt@V(HvvA`E`yA~&Wo{B5CqNp|*8)ZkFbtuOx^LO{TMQKCG-#8{YjkiC< z{Xu9XjEssd)6VN+Sz|y!AX75S86jd&)tjNlDhVi3##C!bmKrljoQ|sV@e{iADV!pz zsFHq;_o`<{3neuZMqPw1HMUV`^%fpR=kyQiE>MD*&0d=6$Ci3=oiusfz|w0)YNXa0 zY&B-)8vD;uu0-PeEloC?n;P5pgf=mENS;GSK;r0@K8J+4hBX*>m2j{w9YjS^b(NEfoO&^ zqkEL-$RCk>9!VwdKS7?p`_5iaIkE8~3r}t!OHLq`VtxM_@t4yR{)K;y6T7VCmoohk zrx`YIDrS*j%sn_JbM}>{Kwk0|{vr}(7QVtn|1Js-e{7y^EeZ9M*FFTD0Ct_LC#-y0kzamZC>F7rQz%7LDOF9|+@buZYq{9Pwd))b&V|BHtSExWu1AssH(_AB zF+3|cCQna13W$G_?~4T3UcJLNA6DWm5DCM1OU^2Z3nmtzxZ0qNc#D(u7BI$8r!EBrfJ49dUFbOj(F<%l!a6 zEg$3xS-d$+{jnMl+~iz$W@l}d$nF*ptju+B{s;>K17LnN8f0|7n`jAEVf9%R!asIEwxL zX__6IzS-dJ|B^zrpKR5tPM$8Go#Eimy_^1%!GEMr>3l3y+UMkIe?W7`Wq_13|0tb& zvUc@!eSVlMEiy}M!VCBLzsR&a@$Dl3GA$)BvP}kJERFY}3(PQC$*lOIjV5}sgzAG8 z{gWLY)IoO`#`m=sLc4_3aS``q4ssot^>c;~-%LUF^Yf6X_$O6tn49a;$&F-j)%elN zN?7oPP*9^u4_v7Vy){#saw#wQaN&*#c=@J(RViq_}i!)Ka`x(Asoq`S>sZ z-B`)67lf^=|0(Y;z)BQ7Ew02t6rECRZHZa9#H_iIJfqME12fOAA#*h2g8vkVD`WGH znb}h^{>Tyn02_H&|ITN@(;~ss;riK=TiRS?qyfchAqt_7wdskO@*6$1!~JI-uO)VkF1kytN}S0dEbXdu1n!z0WQE z5l?k8$iN>gBpYQUKmdZm%97G>f6xRbK<&PSNbLBNdiO)+ds=iMN^T9ARs1k-#m{?V z6Pb8GgAL=i!*1BbV0Eh(v`Q}FsEtNM^&9|V-0Fs#ia6MqpR!O<=w1B0x?Mq zP<0yApE21cf>pHRNcNk(+~D>@HVxVZP@M%hblcqyP^s*MD4%_JO41*kh5wcOItZ+(m(4(m*MR5{TlRxCR z_YZ|?MmTr>2@!f(W=9c3C9zPF5JdsrZ@xAg+P8+7rs#;HRJd!45i$OG1{f2VpD0U* zQ!#yDVB&x_A^XWRY;DxXS-c)rFHbwOPLG9Us>CrRIw;RNHbOooD%8F}z&fopJp#;% z+PM;7qlXi^v5SeNy=ZJN1AK{VY%cRN@0h6K5X_dSW@Wygw(tU+fJLLF6|SrvehYli z0)A*x3ma_--mLcN0XHhwjj55B4v11q=O~o#47agg4s4&8cbL}HP4T7fCM1w?gGf4k z_R4?x3(m`MMkCs;#q(5&01?}9H*q)+mb%Q`&J>KN8HAnM6y-|%&plkxt%#Sf;HhyJK}((FQ!e&yCCQfcxPTAPg*2DE40C+ z-@~DGqCjJaCjJo2hp|8{ehgb;{5@&5R3jbMg7KAPvy)T95VTHfxrXvKg1a-idU|di z(yd<)lU|SB;d>||<|on+-w6@B?2}~p zldUly{3bNQnTU893m~O$JjAz{@ zF|||>|L*y<<=LyQJJpgf*Xyoio_Z&Fte*3z)~Tv^&PFz@cFxYwY3UTu7T;Wf8}k*z z*zG=>S#Vp@$4w>9=cJf+;n5;aArwpo_NzX=rWo)i00qU8Pv)*B)kij7dt@{i#b#&r4D{ zkP)#>?44%S-;#xmv^4y)Up%LZZoYrK^Z5>uX;rUVJ!*=<@EvYn<3N5uxMvirz_hgB znMeQ_r;7C^{gp1*w-ap zx-3P|Kcu&~@Y(dtHBE_Q?Fs;#GH|*j{)KT_58`#1hr%|xWbOg|4F_ERh783K-j;|A zHH;lM2o{Cx7(a@uUI&3jiKjkCpTtwA@2oEX`0ydnGFo?{5U7*PVp-ohz8dN;x=U7YJCPdoYpLa3290DIDH@$9lT?Q}VXpoBlM3zM?F z>2}CW_w*3BTt`g78ma+&0rkJ=;{otcBBhJx!1996Y!Tuc;2TrXV zDjC1K;0{=Kotc>W+3)OQoRwSl;h8QwvdMKjMV2S#&Ozo7yecqRAuzByv<2Za7IBw_ zqUpwRqUPw3_Or0;q+1=BXF#!Bx^6xQ(v|+yFv$gnwPuw>fN99OtfzMY2xr0hc{PVY zEtK-Zy6o>~M@)^v&mjY=o_{NMpi(1+Y^KJA-&+TVq_h6sKQNF?iCxGs6h1QyB)$UG z6}RP08S`SP*cMJqO1VfQ(W~dJDCB<2^cRKx`R51dt0TGothsFZm}m*cWmJ(i0@8&IH5_h7boF|ftTojaNUqt*wS6-vHxM4l}%Y8?eK%2PhJ_XZQq z$gcc=GL|!%3M=yw!h^ZYD2fv@xGPoco;p?Dw3vStuzVu0{IAf>M5*HZ1AOb?bFosz zRs|Hi?1?VoCEVwFOEm1e)}I8{Qo>9m`FmrRv(u?a>`L zc$y>4eZclE^MI#n@ii@xy45@#UU!qV!W;43%qhkmS2K>#VvSgn_CHOuBJM5g&4h!sogK z2Js~NWy$T5IZo&Gxh%dZ5Gfp`1sU{>YVJB?n!px3&4v;F=n;M$bz215k3H0v=@XNSXkY!##O2 z#@6vc_2Hcj-TBJu^tI6qxLCQPjHg%91ZUKhLPa%Rv1Ovu`g`)rPOWxWeXd(lg}BBM zZt;Zg8g4P;PwKmQG`!@s7_F60a+OT{Rlt3K-9y5Mc_&Tm3q6RHZ-A0Q#1fI}JNN@` zw-a6tDO6bB(KeD-Ta7Yd%wHd5Z~FY8Ossl8h9=D~LpX{X&EaKCsYF_lDL3Em0Cf}^ ze4zFPtlOxB`M%`HTu@wfomPLjOPd__lnqzA%9>gWIOxb?3{)os3Cb-(e^lCE&k%+ZW zvY!yuXUCXz^1WP<$o!4jDiUVPY*`_4V%MNi>;GkGBrpp<+eA`kS?(pD?)d#ci{WC~>Xx;CeiOASU<14SsM^ZSx zHf|4bT7KtMN!t3LCUVl#LkwFp;Y2O{U^eBT1arRN?BIV8zRO(=fCOFDZ-_wC5Pc?Nn_cZ^3L20fN zBUlJPE!qMxW;LwjZvk2ps1aCizP|sY@SD2&|4rc-B+bc9f=9-JzV1E`V-H`Zx7Gb9 za}^xAdauA1j42O7-*E!<9m)b8dbzqbLmK;}^$25HiCF%$98ZZwRByi&Zoh=dI1RDB zU?ZMH45pkXzOyPmAaTe8w!wPO^jf3kqSL4c_>EkutW5; zPP5YPR!3>?AbpjbYF@LlZ7B`OYuKKD?f8-~=FT7MmZZw1Pc8kf&3F5Y4wksi@RZ#d zoSnsT1EnR>AJqOSo0Ph9s47Jv8P)<9%eH7#9iC3-)8jxpFDmzKXu9nL4WmKWM`{;9 zr`%vlk!0PygF$0emE3q871A@o(OQ#TLwj0w6?$YbOVAGa>g8i^Du)&SzTlp{8?f(t7z|a31><0r*efzWad!?17 zSE9a+%Q+Qm|3uimyfQQ3VgE+aoQlI)yYkAwhNVo5Ha>To-XFJCYH4GKGk;ia=N43# zQM}R#yVrjKu71?)vW;oKOfIO46Uk0`fQ)W;9R6KeUi}!9J<`X4wB3VKYW5#vR^ES& zS%7@scPt^I?!I;DJQn|(l=<8G_Uj~fiK9glm=Z_n?9PgIpqlDjID}ob^V_m&lB2Ua zVs4ol#OUw1aJ=(Pv5Xq3yo#jh4^2z^L;0@EzojFo7D~vNqxz?uy7#xx*YnWLhX_D^ zw6o_R|IJRhgBIw;t1F0OuNMxvh7GJz&yf=Jrq|a*cdfytC1(PDhn_Z8EVhTK))<%Z z@T4MR2O8u3<=a2(i*_CEP9}L1_H*9*#kV1Gc5}@tbKYWAGb)EMX*vTchx9ma zJu{Ap=zgg;lEr+PkiqR2eEmtnuKIfjL#8&}ibg{pqEF3IT+x20BvQUlg0`tvv@aP^ z`X$=L$))j zZ3(hFDJ6rb1VN9DxOO_C@qEycs8rR-HY*7U)u*Pfa*a=8OL!82L?wM;C6Yn?L`%7) z{6?X4B@d-XN^E=Z^)Xsi@o2SHzt31ygT^#F_YxPKovHnO8x6L_<33->sWX2xuz;IN zRZ8da0lft^YLL(szf=ESc@5E8cuz*3;p(9K>vI(VtzeZd*o-7ll;#~4w`et%Dx}25 zUL4GkycxY4-XmHUTTfFOkp+a}YcwIVsL@n@Nx&E^jh7@CNFR1-hSys!W89elhRqlc zTzfz=5!6}h;=Q!uz^!9DRs2HW0&4=0+4ehTpi_M`n`Ql6o25F>e(=ElEB8`^v-L5o zCh*s+9I0o|my!#KhD`NJ;D7Xu3j$th{T$cCgq*I*JeHEmXC)5v=j?~gf7YPp^K}r1 zkF7vm-8`QfDVTC@^GZ|3&GWJ`yNF6UH}Ofva|aI0rk+kK%CzG{DjBEIPIH@L*;p@U z2=RXm>y4Kn!+Ntu#lmQsXX4BL(lfVY*Ur~y)W6W*yWjkKHNH|0patB}Dr`}}bb&B@ zTCOf6awYZ8{1Dx|;0OP~wxIt9+p+<|wx9w_tW@`vabIW^;-W2a%jv2~*x~!3NUl2~ zy1}M>V6c~my5k9%62^&hh&e2^MQf(s)JBHD5Y(2GZ|3EglW=~=3Gq3573j1u*R)KW z@RgpHRoLn-UVDao^70&rd|U$(<%uOCDEc61DSdarAV2R?pp1-;(c08&4HC)K^W4a(m1RBlQl?({~uYyO#Y(4`Jb%8=f)b-TQ~zF zSes&fJL<(Z~=X5*hrgxt&qu@_%jZLrowz5JWqe!DDxi zH|v`xfXYW1SMaTSPA=AFQ-JRx@lWN40^~&JHS~zFg+tPY8pLLcjefGr;VTn_4(aO3rg*a#SGKa(5vd@ib4`eP%W67QWFoRmkxP;hEw*ZDg;J zPQnfz&9nnMI&DqR$Eb`ojK+vW+W%UO!8KBSaQOh^*HO1CjgI7vPTx-j*(!L`6h_oq zUMaiS_z_+yGlQB)sc7_=Aqj>I`+OCGs;95-YBXF{I{s*CVyus3Y-?ryMlM?WWkvYt z@DFSl;12mY>T54#s4%=D4Q--;1#UESNb|5E0GQ64Do!dRM+$Jn?NX!xOcHPDj-IPs zHsM&K=6+E0Kzn!^@%gW)%NJef>8hY5zzdNE27y`fG*f_`58kPb{m~DJlJKPV+WuoR zkBf3a4rzPyC~g+2XzW*)+a6k_rM<7b@{~f;Hz8=8FMM+6@X(__MkdyH>z3A7&0Plf z$a=_V0M*&b{XghniSSCyJz`0*1-P2y4`)Y^Sa3?OSh>%j;m~6R87;&O9{h=t$J~8q z6yfy$N)aA}Hs>!l+$YBvbe5>DglVWE2jJcblr?rL_QB?Umi=Y{0mEkTU!?BmijpE22Gn@XQ}JGFaJ2*jMSx% zhk0hs-e0Co;-M91{~nFZ8+^2I-!sri92;f$=ltP_H&Sb~ujwSU@gA9{ou8Vi(*Aba z*5cbQH!PaoftD3*Epg_!M$3m>Z-ixIYkE4&eUoeIS`eiVCE)=E(H(Xp?2^oDiOtC4YytR9}*Z z7BZU3u%*UN_NNEN4_Ni%Un=-LxJ+Y_>3tgHs+P+#W=C*W{6$W=!0utLjCQRQmZ}vQ zS#ab|TW_z~QbBMoAPKG}K+xdAisph%sb zo)qp(Z2cnF-8!v6@)_-D(H%p{{gy%9Tb4Ypcey49!U_$nR#^gm&zoMO88{4C;PAs> zlraTiM0ZB1F=b3AP|poqt>A8;1IZyItB`53BcEF}2W~ZCFAgYt?qycBvo4QtmL(5FWZ8|`P1IVPR;TC|AZwA8X^23}UQH>F(HEpksq zrCtxVEQFj!iiTF9vj`r_^GJ2sP8yfU8{#_`au(&!F1gx3yKr1R&);f)bSk|6NJ5%e zBW&Yy8lUWC5O!|59+0x56Jp=Hz*5)xRa$UsWz*0dKQYv5tG}`tvAa}W^mwW{Igt(t z7LM&}$C{lfV}_(^wtu|NX{242tsNf;yS9QGynPnvzaF77_^#*)k)-yDC6;-@)C|ZKPmT5j8r!{V}jN*4@oQB7BjflcLh%Atp62&LZY_IPx zgz+1Y*O&ph5K)%n3beAZs?qCC2AlV!~T!^{y1k*jATTCy?pgrI-5lQpKXv-bJ{ zwqDS4(FTe3zVO1!SFp5kqdwz!ZEomE^sE)M^fsok@%n*^QWEMHbKj~K=&W|n?`2v` zy_G@<+t{t&4{`LAxftu}ZuP#irXG_FD|6MzTDWOJKN+vmJU zq1`QBv3v9)9R3L5@=hd>R{9{*phQ`+dhy@%n;m~~aL)zDDfL|0kvkG5-cuC1-d(dG zd+=7B^2zcj)MCegU#U8`5ZHb>=P}N$nq6te(PD1FYlwg3y6LDpilChdeR@^M>3F7n z6ZpEJ!Po&VjC%#O8|9~5W*^K_v0FldsFIt z?{L=Yc;eN&rW{n5q@RDO#r)<-ppX8)bxB4faM;l_#qJEqYB-n(_70QuZ{#7nyrGbL zJ??Wet`~EyNJyIUCV3Lr3CsNt{s01tM+f{x9vGJvI!0@#PNi`L-M21~eN*pJi>|C8 zot9Eu9x54$S7T#YPNmCBrAxCa$Sc6Fr;Td7$>OW_9y^IjZTQuU62EP64w=wOZz(tr zP_F7ogL6tiDcD&+3H&+)UPFWuRM!y+z@=rE2!k5R_2}#}%V|zjFZ6|lz{E5+%Imbd z(@K~&Tz=Ul-R*GU5bv-7tUYUra+HyB<^PbLml%d?$aM$C=-0-s#t=1H@E5A0FueLi z?ap{yyb5wOI{vFz^yQ=cn*&WoFv1DQExIIjFvL%=#1+V&2l-Ik($87{PuX(j$bsuR zZ6i=OPtkpYx;+IVZqk|s2c^BMBJ;5Yb^Nz{`H~Nw)(VH+`0?EV6{$j#CO;J^d->5_ zn{Bc6dvK)wOKE^~PQ=Y$HpEAV=;u)<*8qV-Dk|x2kTqglwoe18a&j}ek|p5%>f!Ch z83ewchNIoHu)rV4WC_5D~dJOg(h)7Icyq0Z91T}^v zCZXQC5Eic8xc4xNM+CU6;qfysVwOK`U*o?tr%K>wVWTNa0GQw6fH zt#vBtV%h|6Cc%at=x;#Sk#HiI1cb(CuhPe-2IT*0jE!MVc;Y_8g4q-h){4RWxo7YM1%F1EgM>2g};eA6E!ZLLxhDk@vI)A@|XmORbdAA9}8Dm>?*x8q< z^1a#F*|K1~VZzo+8Sn&>bp+oCshKgi@jM0fhN1>KEBsY#VqqByYsTCpcP37_1@Nqk zik&;rM+RuH${?)B>jGqy8Vf=Zg^wu$YN0qZ>mb@&kXLeIZGJ>=%Y!*4@4HE5A><($ zm?+k5K}C$!6Hlc1@l-XDn+mN7$s@(7Zj_DQ&h9q{HWn&s>|FS zNtoW>Y`%Ey>*3rUF$a_Z(-i=5b*9j#HaXE#U2raRPZSZ7RR+W@fAZ;6i^}v(>K&^V z>VD?yT@(ZK0fCg_>yW&nr(N*hO!!CltYpO!E%@n)9oyy&h6j9j>-i+m<2WRL0|9QM zL|DK{Gg4nFntu>FUbKBmg?NSi5JpL?G?~U3l{7B}m>MlM@cd+TAGag&cygJH-@8oe znN>=O?V3vWxq0Xb_)dq=Qo5AHO=S^v#p_)ohFPBK#34z~#6v-5XT(j65p`A~*nJ0l z^awrhrYL5jY%VDJ*b=&SzM|7A2RO;-zFlvThF4v@!qgIw^rQ}@dE{N|RlZ%HwWLpB z8r}%7LND}nKlfPyWyJu}?W5Fc> zuS0cE9{a7Af`ly*R*|Z$8(x$2igJ++@3Fr|E6o^Zem*MLQFlWOwDNh4=TgaLn7DSI zFamHl+#adIP`pqm!+1vu1n^;*S@3~&^i0ZHlon*eYgMQO=f!`f{1J?+d`YSHx&pD# zhCS!Y{EC@8)Oj|%O5Z_%yk@gdiu(4&GCwQ)^Wuo9_KtTTdIN%a0cHKQR#D>K+2?tn z{*-;!I}l<0B$zsy&*^xGQhxpS9*z%Fbhk^$I_a#!_BSTkp{7TXAh(Bf4 zhE0_(vT5e8)k0Z1O{l^5;pg!;L~e+=oLfKn zh?d@?K&4+MN7c)*BVuel6H#JE+t48&W3@LT`by-STv)%JuurZ2UAXa^6ega2-ATw& z3N|;~^+kW3QTg^f1Y1qB15t;39w-6y;x3dZ|K^#qAm?Mo!oKaW<|J({hHHAbZ`@vm zj#in0vl<^cnZE&1f=X~%tS|HLw71T0I`~Ogg42X~y_Nwb)g^9Uf9I;)2ZC(W<~Rgr z00}sO;N91~@`^QHqJ3hS{){B}eLI;vRp&+;)oY8+{Gg54Ao07NW)exWVXv*4oV?*e z^js%21KJR~L=J$x;c?6C_vh)Dwp-P`$>Z{3u5a)oaq=jxeft}G z3Ze*U-vxeb-kydHO@$t3?iDXz9=W0sjy1eqHDt>nWO=jijY&q+b62)ozT{|YF zt9Do8YFsb+Wdx_r*8e%@p8RfYSdg@u`(*}4sCvdQRPQX*HjhLLsjI-`L1mN2? zQavmZx%G`3k_>agDWdsLQe<|QGG$n3HDTR}wLw-U>K`*WkGbEDSf=SiW`<$yjm0+f zSfGf(zT%rY{@V(E#Ha7u50{V$jLjYE-&otVh2VhJdL!l-v2)t23{7PciEf8$Hr-P7 zlfDt%9ksxr){9t%=vzw9=l{adpCV7fF=gkmdsp!@4E~R%{Q3Su2Ig#!ZzYPZEO!f3 zE7F3C5QL$Qyikg+ zn7gIX%Z^7Qa|3`kQ)mnIn}l_{Wk!nhcsR$&;H)G4k?xF}`c43qY5b9!2vGP7w#cuf z`G+*%B;6e6aHr9`5IxPfU(iQb(GuF820l(#c;`b|`-?*$nZBUj>^LC|{qfn-yVFwp-$5Qa< zh}t95B{zQj+869!HJ-YR$nIal=kQKx;o7e?VS`0lP6wFa_6=Yior}+T^3&>K#Z>%S zH;l96FMjApNj0Znd4k9Mg6w$^QCIUMyKF2zA*5SD=tt2tVlSD4uGYX}Z(j2qO@^9T z4TkTUY$F_8^&+%oxj!#Yvc`=$;nW|SLB3amZ*nTfC$T6 zllOzM&AWe~CMV}z*D?Eye5fK14)Znik-!ZK_BS+9#^qv=qNfN=T77Jg;@QW#;}lw% z1_ED8|2G_wK`YJ~72fC+l2@kiJsHlPDlGAP9wF5N1l3|<7T8StJyM~WqP(6AfOVER z{~a~BpYUzj&mvDoi5WN15pzr7M5>f$sonkY+ig$}9-(_MJXth7lktc#J-mj7Iy|kC z^8w1!pFpHp)RjGh<55%78aL70f>yblL&nd9zfJ6yb}_K4D&ANFZId-E2HMv1{7cyD zNsE*DmsC`mgrGF8iT@}hXTMiI@ITqQ+J(Vzni*J#034-8Q`kq@D;JR8>V`A5`|bkJKxYtO%3i8IF)g=zkm~FZ#Y^7$qtqU40=I80++k z2=_s_yg{A6AQCA5oB3y#Cea=nFCXRh&d&QU#GM<|8l_z}J9I_|e*%MC=5;!q7Sd_e z4UNxO*)!Z#`w+C9G;O}Cy00*9aN#yy?B*sgAR=jiq=Fanpo{GQvNYEgpAuxI&Xp6VXLH7bOO zV7`rwU5g!9`}!)HC3BoPLh`oct}lGZ$|-(4N%8c~Xf6gtJ;xPOdH1`v#XG!kY4DcVT2tL(lO77h<+J?Ig%D~n1ZN;yQfzz z>rSzvy*ouheA8w2V^oHtF&bNb9EcGJv@pPhF%~OBnPM_B${hH?`cFMqZ$pDcz1kh&2%fx<)d+`)?;=T<_(5cEq zh91Tb5DqSoep=7+npU>^p)FFi?RCcTh6Vfa^cwQAn9GJHN|<9=#x9d3PupA9|JI@Hn8eeQ|F)LvXp{Sx*aKXw(d-D2jjIc-s zAE@ z_I||BaQAt~kQ4`4^zKrq<(Ws@$7;9^%_ZgtCYOKn6LPd3JtOo40l>5WIv2Uz8h@qn zKk5aVwZrEYaFZRUMxbHfgcpn?#}t_#F%6=SF-Eo@dtFGz`@+i9rqLz288Ug8S&;JH z&`t8m*D}6paixA%Bmea3y5$M~zbsg>X47?^0<1$^%wN*l7sbWhRuDT_@sd@)BcjUo z2g-g5RD8VK)JGd+WC{rgAkwKd$qD2C(`;SV=(YhE>iMJ*u7I&!`dvl}y$d&B1ct*2 z2CqpTfN~H?P`?-AWOHQm6x%`@H!|T=3TPfvUxLMWWKKf`|FYgjOC&d5#47;n?@Vu& z+|(l3STX|J6}b6Mcb)E&8?gI!AFAEZu^gZw{B8CliM&U}%8Ckkh^XsJvi`ChH&ib% z<8T0*qY_JC;4q@p$kndg@9kfNLeHU*0k0?RH)C43$}q6h@4viNj{gq*rbk|fo&NRp zh+O-NJUz?kHztTh7yc^owop&{QR;&2}Ra2(Z0s-O@_bi?_1BU z#}YN(>`*_iUTAa9$G)$Xi&~Otyw1(G-sKF?Eu)g6l^?0Rh-H(%FS*{VE#3t;9e?dk z?l6jiRsv?E2JUX7?__=4(5{CDRy>%RC#j_OZAVRE*oLqIeg(K+zI|~B{Su*6i0N6g zGczb|LK;8W*4h?^Vy7TOk4EK_D8Q^yp5$ksp5%}bLUAtb1|jhhqdE9eZNukCee!gZ z?>Hj2AhKp57r7iC`R5zII|SjLz#kz0xWi_3Gb3B){NBcQ#opn93Y?cw7eN95;R0h zE%yr$e+KPK6xh=XYiyfjTL-~^H{SYqyA(!?dV?0;67v~Gk-XVhCFGBz9Y&$C{ifJj zWK5($XKsi)&ANtK=7nD%qlHOby7uEV-N|>m{}N{vxcn8{?xL&hQ3NBQIp2j+D5_d` zZLlkc4d+g^xGWb-lp3E20IswrT`#O+$1r3e#=NBbBle^Ep-B7*)O>-VzH5>m;u9;) zn&)5U4>T6w{Y~3Yx?cs$lNDD#aM4M!fA^AO3c8*b6X_DxhyOY13Ponl!uW?!)EtW) zd_~?0Ce~~gJ_ul6%syilEe#MCny-n^WYC89wDyWi9HO3(xh4438^ixxxYV*k)4~Iu z)_n*wJm|PV0Yh%SSi;Dd@0^~#tz8=+C#DW4{4k;Pq`mKAyX!PHKH8KyD{JOup`}`b zm&%Y}^82G724fRqT$n5>K*$ordM!JGbr>SCfO$sg1SJjrybIvE%ltvkpaB+SzQv-M z_oG2&2B(1kOKW0yQDmd6q)hBFgu$=tp+?--vIXj*I7W&`8wkVq=jB>UfBUmD(A8Fs zam(p34%1O3MaP$T$r@w|#~S1WPI}h0X?6^-CZkEkSGNp4%FUynyc^1ge34L&Hx_K; z)jRKS!&VB#YE~50g`nHN7U&`QkTRvIloTIj9ZmuoK5{g>IgIaPJ0t9#suE=EX^M*| zD?;ffCni}m_a(Q}>9Cuue}9t5d5J*UoiKG@K@#!z!)-XXd5jMEurR~_tLgUxPlZ#xa*8JftxwS!~|BHh8 zk~EGDNTgxM20Q^7+oJ0!I_fgi-}P0^m1fR|(1DxDHJEetl$tb+nl}C{LbPGvf0WLgvb7$K9<4(=FKSX9UdPuJw^*YA)V3K@2ZpPAfV3GZj}U< z^)hIxb#ywNK+10-!dP&)gS5cOE%-LkEE)^GjlIaqEvRolZRnD0!)L*L0r&yIfs8uy zx)W+uO#x+?Hi3F$S|~2DnjgplWw`u->ZfrVNvrhxRr0F9D=bN&mVA~J$*?)@@Yo;P zwH&;v8vJJtfj54qjQQUYBjoH$7Rw&zg3N5(Ft!v#VaZyAX`={|ok2yY%H+K>@)I(; ziiF-j=Z4nGZ%Z0^QbSxZ!Rn^JOGAedoqM)NMn!S zGMqo~COc_4P^09Kw_T!A{-QZ9_qhlU;#YI_*ZD4svaa)#*xC@0f{80=!6rEDe!;8& zm~`aFsOcn(7NlzAH+)XW_XW8LryUgaEUL~ePl4EwAER8!SFj6;ZZG`4kArlMP#wFD zpFC8Y?PP-zN&z_d`JGS1pAT^xs1&km^Jt}xeILj>6LC-JflIgXSDEi3o%l}N6bfEB z-TgTt9qP8K6lcMEjq=5;CiW5RkRCpJ)(6tr+n15Nqq>*v5Wj?_7+5edJ>nkW0=}0O zeIQ*8>=`hU-C-gqER@cVwch8sk-d3$gn^GODFrB31QKJb92tHlJ$^s5re^zD-zSG- z#=W&SMe*$BXmKVXGvStR750faqmKq77Rng!b%nEOVW3NmT?M$ZWX&3NLCeX89c3C4 z5fpG7I)E^~NoyxhDf(hKbb5hw=dx|i$`4&dC?rkE&^;iAl5TDhe^;Q5KdEI|?Gm&= zPBZ$GiJdJN8*dw0BInm?JB2QJH{jg#la6>#=$+_eJq*9AZ2hV;FuQM$YX&C&V5TQm z(K-hpUFaQM7L8nB5%ST#*Qx<0Ah|PC^N+f>!PM zy)3UibE{3uhOdqzDP`(j!j@3eCc`qatgn-|6v+{p&`=^zh3CvwJ+3~D9>cDX_n~fC z_T_up3tD0T<+ZIlo)fi8$vK0r*XgriwQ1kb>_ZKg@q&kO{<{Z2vPNa#aehkFJYFoD zc5#^xl`1&OmRnlwMB6mZMmj6d43DzJtQH$!7A})ylC7G}`Q_l&h_&O|l0Cqg+k+;- zs9pQpZP{C)b_cn374Wc*G@|y#ihN)Mg<`)pkapi)|GB0P5f@c*@@)iTzs|^@RN-37 zfP|iP!TxKyPmToNi^hac1h$BHY}>b{uph+J!UqE64}l$(BWS;;kMIJq$|T0h{{diBIAq{gh)J+Q?oaZ>df}PvO2Bwh8|3I4$z^n2jxdzHt(j#^u^&xqh zkFXfYGJTbQmL^vCJMgzGpGvh|&Y#^Nfq&*}EnOeyHdo-f)f85w=w2Gk(mxJxb4;M0 zq}W=@2NVT(NagZ#4Z{rp;LbtwLn$lXe(UbGW^`LgtN}3?j9As77jt)*N4m%NdyB-G zp~X|$m7ObxstH6rq9l-wp*k4)`OXb3temnI6+NF41SNbM0auYoq?8tJ#3w4`7cGIA zG|Ii37qlpW*3TC8{R#B}!Py1E0K5AA!vO1xK`>whTo~(&-JFFY5R*S8?#+2;<59ZnPWqUnZJgf(p-VM*!}xA|wrcJBa_uF`yn`I|ydi)!@HfDfY^-Deme)yjJ@JQ5mf7ng|B-SYbLTgF4Mo+&6zxpF^xki>q->53X7P^Q-L=(L zn<4mTa5(SKQ#C4mo&~ZHw`xFtBsx!g`C(cxXkI#f+4`$u~X zJoEKwilPN~$ir#$$YJ9Rq@1mII1oPleTN(pIlbmyor9!@6t!Jx_OywJvrps4yF&C} z28;VU1pSV|zw1Z$Uiz08_ER;R^ZAcHLh4T2CmbylnV@J^Hi$gja-pV#kp^}_sOAWB)D*XO)cg+GI-5;&;n7E4>9#3yCdMS% z9Wggr(9#Yk*bY*zS8#xG&(u3)kZ0W?UZszDg4YPrHO#@f5uD1zrlEg^SF8K?MmIT)e3Hcn$`cm^*!myfg44l#$1RaHR!h+#)g{ zb(Y8sxFo+UQ`dkji2!r1S^@K6@u3~Gm&+tqA)dWooC@Dkf!CBrgue@$)OzId$G+6N*%>T}FzNGTyir$T? zrecJz4Z|_8csL1;=}L*Vw#{`-^NU0Q<)UW^+X*oN@9GuT5uHO}I_8X?WnpO4!s)(P z2%Y8(wsS)ePg+B`yC*hy(3NuOA1bPA6AVbv`v779prPwgrC+y7Xet={OiJT9=j8HV z($N)$8$6n@KbXO<^NLxQRkEh`J#VdaJ0x5f(E#C*icAhhNpFTSYGMp2<%#Mb91mFM ziNGFgunJQVyuY<^HG4*%NlNv5A#Bp)RL{!poeqBERjidHol?*X`jAC;N1yo(_A~Zm z?Yz$Zco87<;KeBbok+j>8;+Cc%IrRPmTOo7;ZETK35TVwFbrBWnMZ|j$K=gy_t}S2 zNIa(NANSY6(w|%tXoX6x&4>_07IZjSw44v({vHq-%7GsH38;R`Zxn@@jqvXQAf}_x zZt9q4HsvFumDOXXfwx%>qo?a zd4KL;#u1EH*y)uy-SidSNbmint7Et=46F9mE{|z)s6O~@k+gEp>?;As=I|J=eTGjA z4q1Sn4fO+^2XhB_#E}6+nm!#tAS|azKwLeO*?yQ}Bmj<+RT367{%rghBQVaI?Z1Hh zDuas|ZD{!6^6`9r|8%o{igH=G@jdSUm`;F)OP_BSCzUBA!rx;JJ3sH=PQIUre!M!j zH@wckOO~L0 z)1%Gx%0GvbnVoJMs8mO7{=V0HbZ;*USzc9a>8i64jKq^E%tnl#=38%Am*sHS6Sv#! zhj0jYOG@p#pGcenFt(N#LVQL$JhpBH8?W)fxF=r1)EhwDs05>qKhI5r68GcuB>`|6 zZ``HiO*+lWE1@@|(ih9-`-Gm7eDX$K^|~E=g8p7!VDn)aL@?Xy$I;l)ikk-C^*dhO zydj9FAOCJLO$T(BK5i(OJTY1 zvXki;HN`(I+JO=MzObg)2w=@d85{hcd;0z-yr1qL$0xI3Cr_*M_l6q*pr*v*<9heG z^|W+UY2r0*qW{&iva+Ibqcd2kljrdAWA(XH>(T&)5Jd)h+)Fr_?16;um;!Iw^m*=i z&s!DtX+~Jr2jg=gtE&my)An%!vi7hQhk5ECH0c2Z4mOc!ilUoiyFL8)Rgp6r9Av== z=ecYC^K&2E&^u}H(~@N(Q|HZb$NYM8r?daF*T3L8fT!C!{27IYvtH%r=cIwqtIoh@ zZPr9)*1zxFQ|YsG2<2$m@KJ<&m1X*U5!CMr@JC;VMKL9R27@?T1cTbdi>KngkIGQA z==Py!#*j=P>m+Sui=~HWM4A%TQ)<5+GxS2UJpi?i{MXn}ZeLW(!GhPEP8b6f4w>o1 zH#=N5+F{k-PWPoBw&vH#;Xr<$^|DLFpnk+W))ca5wDz!F)*pm%C^+RaH^NBN)7Ito z+0mbGvr1_<62$Ngt-TQuT<nXL%=1c}o~p%0w{ zpD1T0*PVfjuxz!97weU72Ig4V{(_?YTNPT}0;v_2*#u7?Jgk@DY^R9Lvbcrb5yzO0 zKOi53XTN^zY#_WRaSKLvR+ctzqkqOA>aE}Raon*bd}>!}v3-f!`|Ph3rn?Dv*f}dm b`lL3MnWb%;V6 literal 114688 zcmV)2K+L}%iwFP!000001MFOFbK^FW&S(A#tmcEItVCIUnMs@|yNd1Xy4K_Ijg`%9 zd3+2+LNa5DU_jEglFI$|dl~@WBw4nT*}1wpvuZ{p&}cNe8|W7R4tU0W{EOtQcRT1M zi~eUH{n^IzW`AG*;#vOH?}NSl{nz_@+uOS+AMCt&v-cU>|M;Y=K6#pP#n@*`%4`$d zWA*<>pI}A)?~g}EZ;xG-ezf6|fM4(JJtY5~*RPl5zqj}L&1Y=;V-c|F`F}3|^F?+o zV|EyYBF@-UD)u)iXOTdO%ma2*sRtXKpE$$kK92JrdFbD;3vfAede!4NCoz*M5Q=4z z<*8uVb(pd!oG7jqUAB-pn}*Or77Gy&%uE7A$$WN=UjbU9NZy6Cm8M|j3UBC96;Bq4z}wu3q}2I z;*aa>X&SOTVWS+-aTcOFlriCPT$g!IC-8t>XBh_8@B1=NWh7jm0Nt4;!1d+4Z$UNU z#|BbEw~WTN=?BtJ``7ZWm&yKI2H|wkv#nnVjoq`59YRO+%ZI5PYaUfzpL@|#8b}LkhA*5aX6~;lRz`1C_5~1c{s_R_G`60}%n^bnu z#a7A^2^g({60O$^{0=Q;Zf1*~6bnp?xl_Q_x-lda@P5S8Yid9RTET4-@WA4z55_fG zTqm&-a#iRii-fzO?2EV%s^d6sx!*qxM$|B$EEk!2z?%?l=sO(UV=) zn}dV#E&G~Ox`(%Kbajd^U(`yW%5k6jS$K<1HONvO)S%>FKjGPRAG&UN=n((oK;EU! zN1?9z{BYr`Fv-#n50F;Yla`A6QU>e;k@z8#9|{sb_WHkS|5HQCNAv@q@BhL6@4ond zpW=B~{?qV2PrO>acRTQI#NrM{JH`BddLNtpzn#J0&7dj&o!#yI-53AwQ#`N!#QJ%v z^x8;Em|fDGSFHDWkCr}|h69#o)7}?Ug7QO|EL1qV&e#qFRk%Z^r-#lf)SiaEh*Q{( zJl3uq?8zwMK7MRXm;KY2Lbl^>vo-;=Y*nlC6)=$FH|Gl$%dBz>ry=?f_r6FnGVyR) zk|^Xc*8b9LStKq{{L7+{lZE zX(Ie^3Xdn^@hs;v0Y4nhOssvX%Bdiq0$8GO9%kBEOIHVlZXEO|6?`T&OSno!@h#Kh z4TjE#)6Y|epQ4bgAS#Ma_$AI%$vMjw3DIGT+oKqP!y&ng5JZ<9g?`pW=PCZbfUw}f zpmdxkk?6qI2Vx4uDhr9+wlU}sC;6`8phR}DDWkc4!1ggucj&VFl zI3X!kNs2D6HMtDqtX&SL9dwtK2CQ4T;t z@xFZp4wCN(J*`XxF>S1PoKheoR2w364=={GqK={TaQyz%J0HCty}dZFEQ7LN(LlG* zt6FSz*;W?L1sFuHbCGfCXRD)|zdeTDA9>?A%=w%7#f!Gll8 z1z&AbR#}o8(2wHtrlE*}O;|O+8r-(!13lc!Sk9LPR2DZI1qh}aB8~Zcne;kLO?DP? z3u@^<&}2zM5959kL{kt?=>7p_KdEJniED_01;Bb)fFY_|&uyx}S1MGvel}uAli5YmnqpG5gG{Qpu09^?z zxtBty%`&cF+Wy8uX=65(g&P`@2X`Ba zyGFyMs%CQ~fY*l?zK-onhQlmPo?VQzhZxT++%j1}f$kq$>tb=Y24r;>J%|nC&gb4O zk8-hsxT^Bta--40TQkd*&`#Rg)nLsMxooLY!IgjQSwBfPP7#&p*6<;X!?Qv4bf(;! zXfPhk!`L$zSGw7_WZGi9n%8uCeaqiWL_rZ% zB>1iHC=h6;BAOz^QQ<6vi8^398bC#t86-hfq(dhgEu6_fRPhXiSAEcPBNp)M3#{%m zkA0VCnR4|MZh}&-3U*iVImJ*!kGmW?Tms)!*~+FE+M~>d-p5Kw1Qq`f3;ot<((;NO zo0yuC6`UbTxt0Mlp($lP&QB=H&ZMNg@vV$>ET2g>L0p|H1jKb@Hrlehah$4?6O*|R z_b^-(?@~sZG6WcL7<8FU%280AQffpnK82m4Jp&z1@<>;?HH>2rEwD@@1l79(O-MG+ z5rWToLbU3=HoXz28Hpub)ld;QD7e$jhP8M);`2$s89&gxq3F5IT}x@F)Bu;-bxLgE zl<|1cz9|5WOxbYAT9j?Uy3^9J?+wMirqdOP{2;b&!GVa}m<1@mCzcmEq%I3!QZp*n zTQ@Tv#!r)i>8;EBOhw+B@ivfDgXc>_A!dMft%|iExVxmcguX25I7{r-G*}Ag=kg#D zal5YV9faz-W~JhwQuf+VTydXKZh)rXNX^=s*daGWml`&t>NDtottSMXPJ{HNhlIrq z!8Gh&!lYdi-(BHCr#4b6Z-T@q3%VM8St3wH(SQ4Lg^;4^I1;ph*Ir900bNicOk7~j z$Fp{8>(}45S}x@)c-E$Mw1Z`izzRH;J8EY5v&wvYPw%Xu9JdT96VYqEFSn;L8uOjB&2(eUqd-~`%u;A z<|nH%U&9S~GH{|(W(SXQolDMy-HlD46X>N_i_xhq=@O-Sub;Bx*7*29O}n&&>|A^8 zffiwE@PBTHV>Z9BMn=qRMN74?0CrRrM3=#T$QDb0MUFCAQ1{*pS~Fx7=j$wK%haWB z_a_;~ZQ4lz>9vJ}RL7KhT|JnT^aqXZcy!Y?1UI3l1YjYjtUwRvJ6H=D`w4K&F8-yUyvvxQBQxk3<{YR3o>#4mbjLZ$r$^c1^_^WE`3U4Mc|? zFVRs-kk*IX#{{Yp{Ro9LN8RP_bmD?sE~6J(h*V@41P0LQj9ZFT3Q?_4tWmfoV07m< zfN7hLbU0RIV6H?k92FxgBOeudt0WtmYXsrS-+FT%E@48jZoFx2!z>W z#k3q^8hr<6Bu|P#(K<~VU#T8eZP8%9IizKe0$`4h>rSC*jyVgNp1m703gl@Vu4)#o0XM#FRVoT*-I);pFs`eK$He1xi24 zgTnP6b!ZJ!?DNlQrwem~_8RprV6DRf=eHfb(F0dH!d?Pt5{QpBmY4OE)9s ztTnh6Q8L_Wm_)mlL3hYd=#|XuUt80Fim9Gk7R{4JAe$pF6Xp3ss3zFjF*K;RCfyKi zA{NreJnl`gwqgS7{8?=XRrEn4F$ROm+8yh$6mxsnw8PrfFKau66SE1rs$k7ZT(uJ_-zYO8AeWc^>U`Src)bKmrYttcagX?Oc$w}W`R(u zs;sOJ)dFGG?hWjuveZ|DdMf#q*HzMAA^EfefVV>#Y@)g*oIgmvrB*w7AA`=yhc3n3 zWp!Qp-#+;A^5|#H`7b)i`>gX_k3El^|KESJx4V4)Z-4M|{{NFaFXy~o&UyVC&v}J% z^@JC=QXb@@wT7J6lrm9^1TjZAizPuoJ~y-jM)Qt>PaER%Nt)C%3a};Qw6;BMZ9I=s zh}w%qd}ePK=<5!>+CsOb^E_n;2GG`~OC3vbSIcqiVSY3`lQC$m;>$*&qdtUgL5{h7 z(XWxypYbI0J&P18?^ee|rHQfWw!-tl`Y_N@*bq!~r(qn>Hj8St|MKI#L8sm;x>|+Pr@!Ed*cyE5T+4RL5UfNb5UY7u zS+ksoZ5>gNC=+tE=_U}B9vrYe)??p_jJF(tK;?OD_tExT$spH}SpPzwr)xRQix)#? za>A{pdnT7NmH1ce8w}Rn-E+6Q?CV{3+uaVtZTC+@On>)t{X4L~JN9?i{_fe|ef#^` z{=TulU)bL-3p_w*ovK!%WF~t_gkk9ZcYqfC@7VquV3U0M&2ZNpeCh6YzuvDX+;w;G zUc3zOvghs$bcuc`OLmHv-Qs1hc-b#{B3|??gF-%s7eIsoEyfAL1{GmfPOc&nNqMOU zdY@196{6~XProtk>_s2SSM@1d(zlah39L39T7PKnld{i+F0jkMhAG*q?m8m6)w4L1 zuAazCc(AC(#z+oZ+DNwa6sPrQBewH<5im(`Zsh75(OibEuvq4m>jC!8yv=c_} z3$MV^F5@v<;*uwmr8JDT)p(2wGqr|Gzna*9Fb?(D>hpbQf4g==w@Osi-c4mB7t?GLYoLcM>tSH7*c#~L5dX}FK8;G} zX;eC__JW!VN)^1cPGZ{eg3TS}K}d&qX<4z04N%mApu%qFg!JU+5ccMv#=Qv(_T3LyslQF@cbVs8|%0_VjmR?`fvP*11f>`>)tr?gQI@e#PwV zF$-TP^ssob#hOgddX>OJOMD?Fd+)2Nt=qE#MCT%lbwJMfZiw2DG2WQ} zeZ9N02V>uqKMMC>^1q+rdCC92;-)@Hv_LQkqcAgny`)G)psuao7GyEiVKiYx`_R^RKQ-bMDf|2AF#7`;MzZr-#eC` z6Ai16b|0*T(-Bv#&thPdH8XdR>CFYNg$gN0$)f_ESIO@=&#ue6%nKsbwl%2^EVCZv zCCirfyT}O}V4V_l=Uk=NJaSbI<#bIt*fu-Ll@`hSoDMpVK@Qfoc|xBLVkp|)DY_l3 zQfDJ!CKK-2n|B*Q4TFu!(5ZBcrYhRl(x$@)n}NV}kB(Ci%})jNIO)Vja7q=H_a&N; zIi&|JAFv$IpE*K^O{1G}uU4|s%B}IjB6yqAAIce@UL0QYI2MuCz(zy!N1B?p*G=he zmJhkF+TQ~6xvm-W*;`Ytr-AwNUjG*S9}zX(cv_O???t5#Mbg_7(9ynADHtqE^J2n1 zxsjnGqoqSr@yzB~F;knwhJ5bc4ho>^R+pDdcG&WM*~1O(WPN6rDmw$kd=MkuggG7dL zW{wU5-L<4Y+CYDDt%R9pSd&UXeI{^XEPl%8+H2CMI_=3neJeC9&YCWFlbRFfcK_3d zXOieGH=$28O{ap6@B(AAPqOai2iZF9LgXruDV=yG=Ge=qwnMLgZkwK(>}gGe?m;HTemY23} zJ@2(w_3QU%C-8+Xj=iIIZ$~F*zir~bx6ER1eEjzObTmG0O5$NSlF2BR@nSCXl#a2N zrdE52aQ4V80uv=|C=!3L;$#b#1R2YfdWe9wYeG1lMu5(%h78ugx0ck+wSVcvE6J)+ zMSrsIdyC^pqi8q%0e4+1%V&~|=Y{ZJJqJJ;P;UYA5~D93yW(kt%cDs^ga3 z)sFAcJuGjjV>VnS#hmQ>Yr*hx083zc9G&`Kq|v&xwiB~f>Xd>gYj@kol`snDvwsB^`-7xB6lKYF zccK~28AVn*I%8WNOHQ5~FE0urAqg=_unEwzx?lhIxAv|opl-N>Bq$ap(-wic*S_yv zyNs3Cx6FFkJ!Z8)wr~)?hnnP{9y4z5bCV57 z2y@pbg2wJY;4~~fCl6{dQG5OAZ6F`6sxng%9>Zw9%Nk~JiSjl+C9t*W7(=yzcnHeGHcat+eUJ zM+`{NR_xM7TLQ6+=Aw4um^94xf!u)3H?Nt!a>)XNoB^woa`2=0hd- zIXKkm03IyN{|9-HSQ@Di)2spf{Wlx)#GQjgg$ZBg{_oyyhhqx3UAnQ8CXpkwUv%MJ(=VjL8i)<`oPW@9K`d!_kBJJy2)ym#VmO4@ z%NuX#(g;#a4FxPwXma9*xI4V<={^n#-RnXxtJ%BayQEj?iH-8J=cR$7_U;=oKVEt_ zAp-Hj$N6xz^{z||tI$8qu^yZ9M0!|(m*%fv0mgYnGkV_ocZ)ej3d>OmyR!7Qmn0mb zYmC|PlsdP;0&@?lYwzr`neSoD1O#G3=1<6rD~!O@qW2xbpZy3@m0rsux`y2s;wpNb z`rty>l{Uj0yLf$Z?7VZovVd_63SLa(G?(t!38q6DhBNV}{$w!`q+_1cAh>1CDTx7q zlmrv9ut&YaSH0(8rM~y?$Y6W1Ed?W4C+@!?D|GVPpTh3}ob1MncU*#K>`3<q1mm|f*H0h}XD>?n@}GYh=hQz2BvGdY^K|3^oG zTQI3}`Ta+?VQk#%3S_aOFR>uv)ki+I3N^7#LE$AMUuogGm@plS$i`B#WmL~9Ae zvKKwkun#B+BaRC}eYm!&gD_1n5E$=|Y((y*uNeHtjJddGDY8JC$e|9F)$&6;wob?{ z+o7&BJTZNFS~nm`p}S4O?;Rm(T8WxEe);mnj-b$F!Fy5tv4Wmhq#okL`Gs1&JYuLj zOwD=&BKi*g{SfUI(?2VLIwseayMvNm2zPtXo4cqV3;>@M5V#M+$&5ZEV_srwfG1HI z`l^a8F&^v%t}`%;~v>Ut&T!%xoXy*Kfu4i=l0>!L40aO{(VpHC>48>wJVB2@D#uzq2X$n1W!?H!m{ZY1<$gv zibbzAhE|4iEf%k;;FU3E&|=7{Fy!9lD6*IeE>3{A#&BhMXOyad|2mH+X`7dOwh%U` zxvg2r;mkE{N{w@w+P0|VK?^i0sEKG~rV|XKV73TbqlB1MjUoojH7Fs=7R8pO#KgPa zHciF|{AoIPSrt6)HNNVBX9ZM~S6F1&B4lWTMxP6jqPE|NnY{}G6jzQg>E=!E@d?Nk znBepJsxb$e;bKLTh&!_m1}&3?;L80)L9| z2L5F72zi+r;1&ES$TO7wtMd;2l;I(9oorshpERCg0BjKLRaOJ1hDF!RQ{fDq%ABF2 z5NjGQuG6D3IA0gvE8%)EJTHOcD~mgTCzn8!_pZWIf&w&x{bez~0M-{jmk?X>(yT>U z7iyHWJE`!HZslpv$W)`#(jlr4izuZe9uRseWq=cxUQCZ@lrgl7hw5SC5=NV5{jOT- zVVs1Tp!_xn5_5EQGf8UhASqf>8-Z|OL3rDB%yJx_mdM{fEufLPf90w7_4QCINTcYd z0YRN@r$T?T`>rQ&E}lZqf=Nv<;fX|xz=Rr1wu0cy2A3~)-K6%kOHG!xhARlgTl*@S zmE-1@5*#e3Zt$!^sB1ui0XTetE`=rYtmRpXO!~l5Hnuj3ta5L;n`lEf)nNWxVzOhs zm_ff>8ca1qG%^4zU*xf|qVZFDD^;>>BSx1SF}kL$sTeofKEuE^1f&!{;VPxiEoCss z^DJj3L$@i;Yos{GYZN6FwWo5d(2GorN=M>8m1?@2W0ARKwCvL8AhCwiym|e}1dvO#I;8AR zy?w~u19Lj{M)!eV5T$H{QQThYf*ULpYgq9DI!DPp=;mzzs<69ktM~Xu6rkPIL@HF3 zm0-rJB|8Ui9pFM9y_U0;bGYg#s-{&;g`R>mm+oOaP^#pUN<@}-BO=_!v{6g1No)GI zYUR?QmFg-f40`3HTnrAjJrmpwuy%{_%$iJ2*(kID(U5^ABMWJkQ+0dr|GI%Wx( z@oU5aZ*z z33ABqi{Xfw2Jf17ExssXM-)$Yj-4Gf!`#jfVZ~EMXEWff2mUQbUjj$ROrEC8pDahW z9NlvCRpj)HXpEK{X&3L{g;Izkpsk1QHx@C2$3vN2OS_sZ1-uh(mN@zdDH#XuNJe{* z8K6%>STG&I%p2mwC<;NhaheZ9wQc1;b(z1FR23ZZQw6S2*6h>Y?h0y3Urjwn#U(G%xP$XgQWo4rR*v;*ZjGpL+ zsCIZdo`;7AW#9(@vIi&=??ZqHP_&)yv!axWcTFX@^z~6?xlrQ2hKBiWe%2;KGyD_5 z==&ff;_YBUs1afFgRwWgi|z@|?H?LWVhOe8-q0i9TcF~XqB0o^9T-H9Gj6S=atIMa zxEgVaz;@++52nH7@guDP9e~mz%P}NX^IS-k;uq*h4qe9mAy$1e&AZ1-%w!&WZbcLAsrwh%^KyKc9Ld(dYO; zIRj8lXfjw(9^wumO3^v_aNc#o!1*^smH}KOR~fU_qa1_%AnPM8YI1Z5j)I8o0x>`~ z!|sZ^`}pCMEc@c7i-WqQcN}_hCwXiM*AKd7fL8^s7(f=Py1#mmDkLWHfLUkP&4bMVpy)WS79ylOWcDkUc{ zFW=+$P>TR+EGR-IRxp67xncsOw4MgE#%e0;;yw}ZH5N8QF;uA!$l^^y3b+oCf+BS6 z>KVW2-LON5^dcP-TIi2M_tt}CUK5~;;bP9VHzG33c>Kr+G6EYX?S9YeB~+QJlt@~q zfpZIfWsmRyB9?mN5$L64T}EB!As`%hP3(?xTZPwcF55_4_k;|+|W<|0Lk*qS;(> zptmB_;V1zt=@?13fx6G)jg7PiBzTmjI4o6G(?&A3pDp zC3C@YyHl0yNCbhAlvRt#mNsk^_8j?;ZxIJerQp4ur&?-&)dqS^( zhS(rS2AI6-MDs;-|0wk7xx;(aSl1QWS%iRF(9l=!@gbOx0NxjnHX!7g|7j1xpv@R9 zE1MK9cMO0TZw0HU8+YOfYufUjXxT4JIVd!dt(y?Eq$`E@A+YSOLOYyQP|%^v7%o#x zncso-ODPOvH1S8QLWZDo9%Ve(Nw%ilP|J#SC4*`td z=1_`OiR}`PZ9~k2inh|?WSk9XnJ1`;U z0%|KsQZ`1QrKGfRnWmLq|0hDE+d!Y|p}%#OXE@7OPReU~xj)TDMRTkyu&DKNZ=ca$ z+4;7H#TCUGc(&k3uZg3wtxZAY4YX($BWU(O?AS`rCeD*NwL&K z3l`Ey#x@5FwMhltn7k`0TFdMFq)wbS5off9v?r-JZex*(!f{dAVI4V5(zkcJ~h0lc^a=_0|s~)|KytnUPck{USbjQr1RNZH;$N z+4+_+V-12|JwcFe*rD#2+XjYC&i}YAOS+Nu)Q>xhJAdfbwH5E8_8$v!*{Fc2K z*(uIj=96pFJvl`%)`n~phQor=K&b@%70qonBx9p#?|MY4R)%XlA=2L#s$Y+w*l>%C zaErAth;%NFmdwQKg6HPA>!ky9q_h552OQKB;u_3^kPtMqBoIs_ErD$U_9RpoMd**b zfp>cgFxq!YLXFACfOCt>^gnAKjV&iJeBCuv_@ckkTqW+!P&sj|VoMXNRb(Ut=Ty}uE2sXKY4#7F9MMS^Y=8n|%-aB|P|Hd@Ta-Y$Q!=lmZ9ckkSpKOB5J?9GD( zFe_#`?M1-=r8r)5S6{hZM(}sK&d!c9@I5JpRf&?kw?z2`z!#!wRCR`?DsE5ZP4ly7{@M$CU@fPamvLyq9e57h3LT zxu4~Jmiwj8#d5!S8as)JeLhd=Vfmyw&}m%du0sPN2=V&epCQ{In(t={%oLF577#x7 zMbN9@5!lm!C}9t{Z>CTS{G(1>1=W30vsuhrg0$j4^Wn)1u0OO9_1F^A~w2$YGLrzp2>rF`+!OIjqVt zgstBYLN~mZW*fKMb7wPeI*P;pbmfStG_?2esca9%)h$xU_oe-ABGELDTD^!2UF)o@2>>w$B^s~-A%#BOHNtcJUZ@Z z1fHmC1Jk*d2#Dw0N6{=iJ~+4|1a5KD8wQgD2*MhB?#vGl&|bKI=S@k|Q83@9{U6L0 zR>uQwzF>Z>z zw@Dc+eaQHY$MGQhu7*1=UM_o4!}gq261Tl&Q6(|mltyKf0&7}D;wv#B@dlnrC_uz) zGT=>225jUu_AEHB-tM#DRau3JHm&{?xS50$u}(;^+Q|8DeJu9yw-u<`aq`2 ze8vg*6_WXy5k6$S34w|?EHlbyh-C+fZPJGNY>j71+xwPr#u%vD<9ed0Dv}k8vsVbl zeN)BZy+0lag~I;l9qk>fSunIG6>~Sx-dT`@t-;q64`I`sO)6Mo=}Qba!1!MBkxAM>DWsE-w>oc6@~SgET(Xipo2 zFDrLhxr@nNHF#QPOivmg%nt0)YuV_YvZ%HhIrZyFi{)$pTC7hSXzN)do{-92;7hB-zTC zD$DrVdRIwG>nr4Wb!ngt7Rv}0+idn&Gyd$gH};CgpN+7rjX&E)cd54b>y;xQUc|&v z*|<|7bpy@K1yQz9zn@qhm-<--6|mt#I_YU+xKJ$=PDQNMhYO{{e-SZB2j51*h0KGp z;X;=GIm_UG#k64{llk#6ZD5v9hfmg^L7CwlX>=<)yhE>L!#m1CO8XNx)Z^@V;&qG2 z#M2GoXgX(04&txf7G!Ba+i5@*5#uS!6`M^fvIxR9hi9}*o|hPI8^SPj?^_#eR}^>Pc~ZxPO^lT7V=Crupn3A2ZVTYgwLovqlY z3tqk5Q5Us%LMmliebhxd0VyIa>)_i+)P;FaHtNC(RE|y3(juuVKM17_!k3l1tlU*1 zNlOY(%Z%blUr%T(d+si-*d9{+bOU`9_-iueCx=X| z-5_l##s*Q0rDbku19`EO#SkH6ARpTtA=ED2b8`~7==d$`o{7?#F{KSUq~1t&mUvO( z0xQU$l7a9x4yi0e7Z5AflpG~%o3}e$X_H9&%7nF6hBs{+Q`sPXQkMkTV5y8?sTQ-I znlV*x{VXcdSl^HThL-ghzuQhX2vU%e^8DEWmU zUXlN$$0((t!UmdVi&2CXc*>yjQ0e^xyiD{)cHFSlBSq^bt0M>E0RKY zvqMF+N;XoYBqVOeO&zu5k{YUw7A?{OV)cZBMV4@}Pd0^EyCKdJi}n+XX6320K#>+u z7E4sJWs7Z&4{4Q#Q-OcCAyz~~aoJ6gokG23F1t3}(o+a&ZHz~8NGvE6l)3_-s`<@E zZ)`RJUXN(i%CL^7ME~1D`fJh@8;+3?j;}bk-jRfrENV ztb-X85~_xF1%i#f7lNe%HYHTJMd**bfp>cgVA^*|!i~xCkW^#`aka0;riGBd?pkVm z(O+pk6!&JR96UA#Fx6eLB10jlw~C>xXkqW}{SBE-?fEMuK2oPFQg@>W!A%~3oqMLY z(PB3CcKM4v=l>{JeCN*m;o#e0Zyqdwb1{o*FA4@I)bX0T`r_>};=j{%c6OA3?@3X2 z@zTJ0LM#d^WEPEEBs`+4pCe1!F-F?~Xp7ni zE+=rM&tK%RAiGH-1*c-m$Ak#Y=CCfu5cPgTh~DsCnr_^3&z;S@=_n2y)b%E&?a<=O z(04>-hxJk~x{zu_ma$pJW*M7t#VliM?`&$%zoOP7@Ry&Qe+Kif?mSo!^5lo%0{IJ} z$M?b1dC~hT!T+%vc_VaE1tTvxv32w4xT6vHudWRo=vpEro^u~Xv+(%f;EvF`#Z7M* zOb#H1YwWo*KRiIg;{KgCB~3@ce4qAzFk6hr2Zx8hy!;7AMk;{|cK`7C(W}E3M=yRk zGO$U61en8aE@Ldp*^>oidZ4VvQA)^oD|X)|J+btuuqA?1|;AIrt=R ze9K}|67nexYnxILYdS^ZMKR;-1|DQ6LbhxQ;+Cf%PGKeX;5e_|?t|mi`GA=kt^Uw> z3ehNHk5E9ikpts~;n?HiR%&X?VR0*36*$?xb_vT0S5~+xdQjHH#4-=;8@XQgaebwV zJ*-~}y*Tq}Z(8;mQeZiKUOSh+c2fIvPvtj#Z$lOlSo=u~OAp#h50-XE!`g|**3*qt z;;_v}?pvfKZq9uS3N9DbPFr@mvWe66Fwgjtc)(IsZG^F8oUBj7Ona`rAoLYu?cEX( zTSeNkr|CC~wysPfYUPRfr$NozK*(#+3VTXE?cIDc+-;Gev<@kk{QTo4%$$=M?U_G-n24M(9>*a^#<`TBpzGvH9NbF2|DWv*0<4M{=v7pIeS zEEn`8@5hTnbh#dM^y;sFQP%H=!Cq-JYt-`wTo&~Pgw`9dowkRt)mXk%Z-5!*H&Bkx zNBSpVR7fFJ)*GPH$2NKcs?!-WwyxS6kb+c2l+UnnZ-8Mi)*E0s@>Y2R*3P{x<8ICy zU?P#3-T)&_&GrU_)*Fy*_{#vl%`yDdkTa@z1J+K5tT&*nHz11=SZ{zO3M=*otet{b z;-Pp0R03hW0d3MsN_qp#=vCbtK-(eZ^kE39j=DmN8G$lyFmc1Lq$*`O@B^#=3P0bG zU%O;m?jbu3{>#&QtjBk7MLq-R_vRBnglX~n{>&Z({0}yfRIq-8t+85|wtu};q5wFX zGCvFB2RuxEl}o*ug$^6292BJu%ePk)-d3|6L)Z?QRLQWzqSe5(kJjg))6zEj9O}}f zEL2{#{~;6OiYUECKyJVnkvcHzk+8g-K5OzztUv(BcT==P4zMCXX%V0vQO)#TWYFSl zABM4_^<@-Emh+84$sc_69^1VGY?Wf_#h0x| zSC${yk_z|u%=%7;{n=UBcCvq$yj#h-_MXr(Rf3i>>lhA$nYWd+U!^&8B?zVY+&S!Y zoz79`OGyeNNRTlnj%|D~Gd|(toVbsm=g|_8kC)T3tfj+67zLBI?nmA_8`eoOSE_O) zT1@#5<0`_j*WtZ8oqFRZwUBg5V&^?nKG_Fp(b%i9<3^*#`9*7npB}f9Z1-?XYO&BA zr|`yfihv1F`=OGe5WQ03q0}8fX`@_boy% zQQ(vL-#l_STV3#jG-bg_rLftAd>ee!g)ntbSTCl-!{Hj1YSR@q;LD9tL@W=b2^qs+?hU-}Lyt*^uNN~iO2S@}bv&8hg@Oc9kS-gDam`IL zG=UTD>uQr(V#(bA!J3fpS%g_AC*X#O*6r>vDmNSli%}0OZe$(Zad0>IcGx43_RSx9 zVNV}KugEI)21LyABW`nw-zWQ$6jdlFP{nrao*c%(O}PQJ>m?&&0E}T5H)BGE#*eHX zh3WS}bUvAlJxEyZjn0zn;Iu)|hXgY!88d|LM(+1u8cZHV1M0{ddnun-z_01k*azZA zKlq+xkwubisKUmO?7d+W=8tR~=8rg%DB67oSPL@2}uodWrAz|0LZgMa59pbpS}4$?sB!IDfE7J)geNDG0lq0fX7Tsh#| zY`MO~%Qc6UiYqj~R`b2xa-?A(sHyb?6-Pw$Ys1q*?$@j1(14w4F1WCItQ%U3JvHO;{%q_<1VtwVXZNbivpm*;-X|-1fMI#cp6W)?a@5(PNLEDO&4eA;BpF!FLFd;Xgqr}m5CteGdnd0?#j?%8#gYsLDGF!a zI#L?aN`fH|AoEBWwPtAcDSZ7|2f{+yZ-E-RtqLlAAydl)O~Hu8fi%sMb*_`H`yh-E zazz7HSJ6VS6#<;NRb#_|TD2f$Fcl8AiF2Sj=qGJtBY>kkrE#Dl&wQGAa5oxCLUjsK zApG}}wH~|Ey9I3BW0z!$vZ&#*ZL`a^ZQHhO+qP}H%eJlVvTgI$+WXwIFU~)hW8{a- zobkL77VxSWIu?BQ5>dp0-(#dg$N9>BqK<`XTmznZ50T77IF^EO94rh3rRV-}gRh%; zmuEsJnVQ>5$r&T{2zc6Z=JN$?EstC6ZeIvQ$so1r7pvL!myXF(EB+k zJLGfWU1-eQ%)*jaDZ?_RU%Oj8E)#d^e@9w5VT?FIgPmz+WV1EU_qBpUCV;{LM=X z9;W9T9p#$NwHZV-+%3a@0*OEu+M`tzpUH8esu${kxNY~ESW9%A-w_j^d;pGt+I!eB zycRo8a-$u;3|pzjZuJ2QgzT!6?y?;+yZ&^0!JR)hI7( z4ZGcYOHnM{G{=kg@!>#2B%2Wgl8Q;^z!;mrGJ#ZvG3$sW`hW_Hqo1rV6i=dwirF z&*ohlmvyVJ(|dp2!5+At3cHs_^*FvEG>qs}JSdyZN^I&&A9M1cDSwNT+mw1sKA^ zNEYvMuyQ*RzyUo!@PlB?_XwNoFzdk(hj;vea8U+!?Vw}^648p6PHD~-wrot_t*k_K zv{@TYmWL{$kR<0$OinNK8!*Btw&Y8~@+y5MHj;MLi{!L8lZfnCZ61&m?RW3TMB!_5 z8W`1MGA5G#%sU9->sH#!V|=PG&+mLG&LEZf?em3kYLuxvm?t;_Y++0Zc1#qEdE`1J6_2+>kjg0J2>W?b3VfZ7?T-<-Q^@PQ2v`&2J1+k!4WQ@Fe*{a9p=kf` z3T4wH0Gg{@1m!EuQjO6`t*;b7wpj}#$MQE)v8l}m6mR&fn*H={2s9_yM0GY16s5x| zByc1I2!d=p5$JBMd;*6w81kj5!M>-Mm_9NWhNXMb-kTB%(SgJlgugyjLX_DUUBUrb z*R(CKMB>(okqT8hm4eMpRG!akX8UMPHZ z+0738(`p>>7OcnU_lHA#_BqE((DTc_{>UrrQXJRE{As}8pBPt-ET1Pkwp_uy@A;U~ z?PEXZkcQ_ZzRnFGfkpfhJb0Bf<#Vo6#R~~WyI)jGW}gySM@S_UHs`^^GL7K3CZXD- z{YDrbPJj+v-ugE#9T=}{AgQ6xhLF7aQz4Dvg$-`!VTuvP%<`s<1os$C*UT*l(G4$! zpRcptc%)3IAS*u-)E!t}BDlIe%uQq?TBF|UN*7ZN=_{!dcichiH>(B2!;V~UEDvr_ zsqo0nC=Qu0HB|qkb=Q7xpR#`kzf~H|cV3tTv^yRIpS2{m8+3 z?!FYk`o^=89XAYV(tccf9?-Q!t zr~$2&la#a)!rH!x^j*1%0A;nvc}gHzjqW;>wni{T$R*pL+i-KwJ|4elfYR4sp9_!D>|CF_S+ zI)H%Ge>11h5~T#9Sa4s6sl3on)2N+9h)gcn6S}m*#mBGKLNVLl(yA1omRKne92Xj@ zG;}8W>phS2Ow9s;G2GDh7wOC+qb$GiCFG!BUD$O3R%CJ7<4z&-G~K4Y5~u24#!X}N*QPkkSDaiLWo5gIZ;q=_O;^x4qY-X>`=bFKy%Wn}0;;oaF-PoBZ=PJ!wVaS32uL`ADJT!35pY<4H8;850`p zC)Ro!!Fkcssa;xj@&+^vwec^)e>+!SpioS&`e9+z@+V0ao5IU0y`H2c&il_T2iw_x zi5N;85l_8-VWm9>_Ab?0YMRb?J7s#i3<5%VXnxE{F6>EVus(P{V+oI>$^H`Zq-@QCfEvT{J#&=b32A_tJtXoQejKYEtZqs-45mgd1=^^#>uOCfa!dMmdra$-y0ntVjB)@0G}VTw8)4TE~pp@P`! zWg~a3UiNeow`KXf?T62R?9)E{G?_}`w7;U(0v zU5uTg(U_#WJ6eQm$t)xg&ph{)n@c3LBca7DzmFuOa5ZOKp%Ie3O|2oNnLtQI3hPa$ z0^RA9EmAg%P&CNLpH!-jR(1@bt1%8ifvjem#k(nOyK|^JK#d7gV(ijPnz}0;4RqR5 zQfE-||8O#usr+8Ce)<)xh9PMVn-`PGx|O&bL-@-&z(HvJszu4!C4jucSW{3X+-JaX zj!_!*2=!-QNODPQse%+AYn;(>Vz&2_jl`UyxO}CuVN6*FMUZ@jN@{9ia8c|@zNS(u zgqD^*dj*l0dQ|1`Lkq*J&EW-2J}M@RU*}Y{6?&D_{fc*YSBmSZGW%c7$@4z~wJDh! zoH7lPzm?#kB%m}o+8O_tj3X3lW$sZ=yujOvCR!$wDu`$R_EAdMoQrM!Qmta#^^@@M zfpx_m1X7i%&z#~UYq#78p=hDhN$Gm1)TGcPl5MCY^}`e0j`^FdP4pYMvr|azJgTSS zPV~1Au%BZs|By+LP=H`^4$_{o`Q&oV%=V@sb~+?5QyV*@S*P3b!^lEShWGhxpvWL< z=Gt4W$F^hLbeAOB;6`j;pX7GG#2=Kp-C!=rUeCCN&zpsVrKzPOt=8Avkt#~v(s8CD zp9wM&D`qY@PYtX4>pMhUU zo_pIGcKKrsd|d6}`8sRkb*Lrc{vpHI;}kIalT*SND9xCNh;A-wxypH;on{vWFVj;o zy5Hfg_KbJ*?mkcF<7KUCK~2wfeA?N)y;#~g-S0O~2WQcGT{ownuY5DSy1B5rdR<%` zeswAb+puobrdv$oYBFt@Sr6f>?xjoQ?#spL@jCpw*l7qvyeI#ZOvbgx*M8k|*!H9F zS4QmW2t6;?VGviQcLNBwqw=Zzg`F4)crj_AS3K{FNq+oVB!;)#xgP-gBfOEY! z`T_`-0CvXg2$3*7xOl}nO49WKeYBmOrEFf(Z|<_Wd3rrVe&fX7?|UaVH)(ob&M$Y% zRe5^dzk0{t(Zj^*d|#99y-}g-A&A|s*!?oW1(H>0uiry?`8eMFw%kJd!yza}XNWpB zzoEN4o|2rfrtprxHhm6oc=$Yby98zqyL`OfF39d4Yxo|*XBY|@;VMPQn9>kLze>(O zfNAj|OJ@|W+nb<4IWLsVuKC2F|`@eHhS(S+^h6rdmd{g_rK+x`V6Q3 z#V%@B1n$Z78eVST^lgeL5j89(c0`RvFe$=3H#1)1*9Nx`|-BS;qgs(>^HOBd&P;TLAem~?86#%n2ue3ZVdlHqJF1j^lO^frC$BUV_TVZ%<5_ zYl%#x!$Z^)1d$g)V%Pl3z3*uWH)bc%b%D&9#$sm#|9#%bJM581!~fe^_u=a?yL5o5YH~jzy?|xpI5iwPE-X>p4zz|w`>%xceHU?KmgG?# zg~%1l$KV!y*e)%9ii@+$Ly8s~f}h!G#8nH%qw&^XV(usG{)YOrQ9lp9$}=YlG^B?T z6}RqYUE~agUWd8necS?EVgIi+@9DFJ9m(IQ4pS+|JDo{etwOrtAA5>x7e^50=*T;4SMd#m7wa3KHgL+5ArDkI`*e3tzcucb#JY=l(fRQ3bOTHvu9l84if}_@)!{?S ztQDC~0K9~;Qn+&BICnori0;zr50H~)XJtz4yVhgksP=Hz6M64P!O1ya;|ib7dzu?j zH_nBGHL?px5qZie+7$I!^c*eJxsW}F=S9D$Ebt{)F!EH89WUbT30U9-*+oEsw-{jS z7L%uowt`a4l!sTTrge^iS=*;M+rvofraLz(kUN=i01KF+0?eUL*}f0i zM!39=Nx)vCBC#Rpi+(jK63-s#i*5B#kIBm96+;zhV@S{oPm|b_yA3soC?HC_p(o}! zq-aSuJF>CUWh8d61L_}I=8cR8(^HG&x+>iYtjAD z-rn@zrvCA;`+l;4h4l5Ohl`&{Pu+1@@V9>yTP9uC417R13#V`MJFU}8Yd!xY_V?ZD z_hRx5YkYNg0yC^_0$_vj)thj~`X@NMlDv}0H}t$^zck&uo~4{t@GgDkb)&B5$#}oW zX*LN9uI^&{OwMHsQ$Q1xu%j_pqm_TRRehY!KC7-J}TE8XX-zwK*Hh zt{^tIOF=b2xdmSgJifgNF})(TC!{g6W;`nZT?q#nxkpUC_ohp&fdPf0;tP3PN|_xU zZ#N!!B?^*N;dWqfE9Fi&*M?Gw-KJ^(I-6&BI~EBVecN4wwRf+l<-BBKq(Sfrp^JU& zqp_yY--<u8-P~8qIegm5_!Ocx{Xxdg01TlEm=|R+STV;BsN4%IZ97lc?q4 zB6bD-sEl}qAZ-8#i3V0MTXeU#^fr2+W&&Yj+gNMkD;H%AJ(fRG$M!Hi02zRk+XA2Q z7=k6!YGKBBQAdOUGY$z;huD}&3V%?noj!Q8Xl61~0Fdd|w=~Zj2Rpf_ota&S@DXgVpiANO-Q?Ku z%!2cs`wXTZ*Lww}P}z#sG~<8{Jh$BVqGNIE+*X~mZ@E?Xw$ZUf0@+}PLOo~rPTC0Q zqeze-h#~$$pbruTPj0yjrGb48V8s80l9ByDa0_eY*&HP_$PS&Gw0x?4p*>acG%Pw} zNFLx<@Oq9($EWMgLI`l*WuS(htUA}pz)&sl(+n21mPb7`08P#64FpxEoJ%vH?|!^S zbAq`_9n^9)>9>#TdM;O&SWP!oi$C80i=u$an)t)jX?^5{;SJny{}XZ9bs$F&)3==X zgoV5CVez@iZp|BQ&Ji>Bq$fJWd8Zb_$jTXf zM({n7MMV&}HzAml{bZ)|92ZFv7e+g@ge3jJ)E5fZH!9a0>~L3~T#ReF*4hI*`w{Qg z`dg^J?@BMQ<7B)+oPZJXPxM{TN`?Mib;1VEU>|k;`RIu%F|J(QGh660mj|`k-;S~R z^qmt{KayPClYc$t*R_R4lTjq~>2e>XQYJ+hva1>C z=N$)}CUzA~5O@kIYMYWcXL5Klg&iTA=_cEM1CoC%g% zz@#Bf8U=oN2bfuW{K5rWl#Oy%iGb{%`^#5g!nnQA29#=yFGPB{;t7jvrQtkv@{YnzyeP5Un^JziKj|5T1bvmC7LmchGCjW=CG)iWe=mdMg08Kuc;pS@f9YNcYtvN69^1VmJn3DE|ITXNjO2v3T}W;s0Kq2B)_o>2S$B%W8%W94SX$py&L z8h>90t#$DkFA~a8QIq{2Oir*d$mHrX{Q~CCYQzsq2rCqTj6+j|ePR;@KlgAv)##1m z<_yN@tt+5n=Ei21H8d#`JA%FQO-6GXE=9_WczavARG?m+ z#m$qLZB535DxKB4ny9z(;{bD^9#Z(INHa%jqmtaKO^Z7@?j_`C6nu>}gg4fV6}Bex zICF7YW(T+luDH|CF(gfILB3FSVL!$X5bqdS`lw!%;?2lE)sAsLC*}5w0+oZad!^Ib_#GU8mT0W8|jw-KL0$_a#XYOuPr| zQV0NI^?x;{>j9ic<>5xy#D-kRgw%Cc7%eLHlWxj3BLS-_4OUm9#67{B5&w;ka+Q z+RTDlWX85~q7Q6QnMJzBr-*i{I1<-_lgid5AS`)B240j#vANa)3w8-TB^WN+;a$5EL|JGor{0O+ zU#7&PIvaN4imQ~aKx`jH#Yvx~DGPDoBQHB{;sd9aQG(&zRUcCMpDiAnFgi-}MHdt- z7BPw^IqB}GZ{^uFGzDywif%(vO7tq!MZu{kSiPk+nLOM*+KKAuIt&Jk6KzLBcMWvz z>~LsBx$(~KH<$IJj5J~0U0Yr$nZ*jP~ zF8vDO;tTeX#H^GlY{RQ=NED_bft;eT>X@9CL{d$xPaL8|niORgo{4GpYQFJhA407E zF$ipE^}%F*88UL67W6-@r*Aqt$In~jf482pKdq-J{o>I7(|UqP{SU1thxDuS&i~zd zV#5A^t)~xJXeN-%&nDoFNl7)(`mDd&m^|~dqn9_?^6>ER6MgUi#_;lQTVXd?`Q}`k zW+D`**O?Rkr{_hIK?Os8u(0==AJsCUTLA*XRoB7Oa$-S{1){;H@FQCfv>jyZt$yb0 z#$-#GUP5vHb^(!kk&-Ud)`kc?Gi@cAk|e_9280tShVb1~&tCMfq;dEbJ|}R= zBpN*#i;cp41tD(3TOjm&Bhqg^X5gkBMY_^DlEf9Rk4D;?{vI0(lP`Uk6|WeZ?~7ar z5htddMs0i{{GKRX`D}>O9J_gR;;qOid7%UVQ)OG?55v6jwSXw7nJ{R{y=_7e1TM0? z*={-X_Fu39egI74K1bFR6l?~3V}=n_+1ZpqN}PtB{N(YV4OWELyuR!tUiEFKd-=Af zE~U8}5_ppXk3qH>2!xcmj5y?dlEUm52zcDG2EtGXxKGPjPPZLP`F_t60S2Mzg_ zSi+HMS&FAF+-S6Np?Xjus=J+|1{%3g2peB;A89Ka3MXOsi4r_;<_x!K?QQ6A$Gn2j z6geOCXlM^WUF8*iFO$1eBF31aUu^dHBa%bJSlvowqo`Pl)z9az?@j$#al$)XUOem^ zJUpFUI6v>odf(h{Rf%vu>e|Jg9I!|g0{_H1PND7TK~@GQcriT1wh;M+V2FBQpyMEnbpoThhWe6>$u1I#yUjwg8QfNGIuoR1A9i`i=?TycR5j#7l&kjx zv>!!6PAzz1!C+TaQkPa{6 zgWJ@CPwbHKmk*8N_`4kr!M%S=Tr>yamA&%LQawAWm>{Y)qn{F?)G&qky(urNpAw-dfLpJhU@ zSqK-^1}fTBrIYyPvJ@g=RD~ora^;oDL>l=j;@u(AM)-A`LNs z;ie6o3i{rFJ7p5ZdQY9UwI_+Q)ZbDoxxE2TADYG_sCui`^RxU_L|B1v>(hT9ltRs8 z-cmhUmn!u#2amNn|Ms2G#I1UG!xCj!tjG{oue<7Wr?Om3FxR00I3kISNUz$3eJ#^! z$?$NLaDa+7ef|yz<YJk4^5aLIirgLbUi>PI0GMr!jR8wi#uWh^peH z!&J%vOcPas#CgniOEH^K*oxx!lov7eFetlsPe~hW^w!;rW$GTv&(l)K{yc4}VRvc^ z%H%&!Ya7Z@mYcnh4OFBN`ImpNx}+_-ggq=*U8;eE=DZc93^^Y~$^rW%oo+#y(nTO7MJI7D=zfeJhI}X$1@JQnXQDj zY-jt0`TbwsaaQy`+iG%i)Hs1k`=kNWN);|P0*S`9|Qt0SlkFar&m~-gWiAL#I zIk$+@kD-JI`D1nPZvILz=D zAItI!vM7i9u>f0{9!HC>Kp`QPHY|4=*b7>hPEg|sS+zsH_=X_VL(+U05q_P>XmY!X z4uoyAWJ^N>8krMJFsHTxyAuYEr$NBz#G*V@}0Jf(xJd7hrO7{ zk!-%kkK~$N@P+r|))zA3Wm^y-z8y}@0`gxVNx7LC0?kJjfGvAs)1j2UAiVs{fgH7| zF9s0CmeyaacO$w78ND%|^5zU1h~oq=ck70)O1x5scy<|#7^&jz$yw3>bY;>IpUpZa?RQz{?+XkGLmU8efW(nklb6J3O(tkb_YPpaH; zPIV*pxnl}kMnObQH__GxCX!m2_@{YfW}N+=Kj0yUfmRi;VIr(_j2J^6oI5NpNs(^~ zN74e?)3-7~-~w;a4Wg<&bR&F_lHZlp%|q*fEJImO0<2&!u)GedY(rMKcfYuu;mg;NL-`I=KG2P`{t@yQp6SPB%^}8c7)xQRUy$==# zI~1~#fg&jD^qEdgETQ?QP8W7aE@Q4$HeUG~L+4ghP>fql0KX@}x1Q9%)vXo3V!)=Z zYq0y(0tf?|ygw_R`(P=iejTNoFoGc@bHY$Y3YP1JdsD^U``)DE1EHgI?iCrkg7JGG z=p2$Jkwbs*dV|XkBEb|Wtv@C#y}s>17hZ(#V>)b7>xJKCQOsJn80_CJ(DKIxR_YhR zxaXm50-S1g|Cb9)fNQ1Turx*4ZUC4$21#yNTB5u%4|{eyB> zVx_E8;wrvwKIZ`CF&KB|KA#iv-y@MYM3NpcjAdtjXs_`t>6p9J7ERp0|Ai-26Zv3ueyO3IIvqb=wC~soZ9!1c`On|EA0tpW3H-mF2=Uwe$ zBLjy6W3XQj4jTQqyoS1djBV}HXxP%(uW1-Slzjt(Dwu+XP*|2pb&8aQU%;tGWyxkz z!UsfIS8x4CmmZ$t4~u`_^0MQ$e!YM>P;h4~0z-ro+lhiG!4$e3yFrJSLgM~1A^;n1 zuC_wZed-$%!OArnBnA&uun&S4K0&n64Hgu=AEpl+t0OBRvceEliwlLefKIC*O-o9Y zS>e_8X%Vc==}9+~HsBCp2o+1zR&q9Uj}B6{@l!OKeegA&nz)iuaFF4VFhgUOX-O1d z(zOS>gulubhpfX~K%9Fe^VpTUPM&Lt_M!B|;P+mbswDje^@|o}ky+i7BMb^5bHekCza?mE-xVUr{gBL z2g8WwVt?}{;o2Spma8lP=PSkXiq=7^zwb-3Jr5|$>=vug*f;`?Gh|T1N$@ZXksV;H zG8>11+H4sZ{1Xfg(LbJucDGhDAxs*q@ej-+DkG*(&V|wWH_XHSfq5eW^$!wY{Kiy2 zFz?H>ZSM!>C5cd>>Zeku{~PAL7BBg5zTqSUrbQT5wW-_$X(*;J5Z|4DglR7}tb9Ch7KAi~-|E2Hu$-ZNg z;Px?#4?a#<62#};#K*~VQ`b39TlLrM+jal;;T3<=o!;k5EKQ5h9IMuF)aa09{!OYQ zff{E#`n{TKeCS|CXtwLmfZ}Ju4dDvSLCU-k2B$am%PT{4SNltf8?atkRDz$7zLEQ^ z7qy%@je^62M6owRrD-WqcY-;$y$TN;###p$$DAB7?fN{u`7a?W8G=Rd z23PsTFlES{w(@K`9Meg!Q$cMP|HP3IUu96@MQ*2I#^iu=f!L+%KLMh;^OQFO!wby* zh$tWmSvx?sD$@nYvGTZk2kRC-%Amaag@;t2nM-tMAde-!`#UReg%fBf0SbWP6{jFH z5!_#y-S=g!0onN2dIBGzT=!x2bL#HXh1xR>iScSggHUP@(zdJX)4vjSfcUc;S5j^6|Hz{UCoaktgy6dQLN%! zK+aS;k;(bty*ERyH@vkKgQKP5SU;#^Ylnt<;y()wjW)&1+tC*KZ3>c<37+hF(-TG8 z7sABIs|Xxzujuq7m@!~YSw&k`+UL+;ik+XP8ROs6uV2fX;PD3(UtCn}+zOHo1>1h* z0cP3be3%PL?efJJGGc}v+9O25YC3bx?;FN{T4@WdCHm0f{SDoM#W&;%v0l@vG$<7V zBa0`&o_}C*ER4IHgUAs4d{X~J0x5Vwu##Ao?_5#2N3T7(0_txc6?Ok z!1Y>|-Irh;x2pMQ49)Og9If50-0h*shf>?t>dJMLavx{;6G$m~Pn!22mEKYh`-$7_ z3X}sV^#EWf7T|-yu;|L@##GqnTY?L%>%M3PskS&mp#E&fIdZTX)y_rSM_KKV5ruJi z)-oGi>br-O;-P9Vs)V+@Oiu-=&H$m#+t;L29FMJ-hq4;24&4x}QO)3**zOw^Nbl}5j5ejC;5olQ3xS-LMsa+z|aa%JNvYJwrk_l3&o& zGAbiM%^He_mQV9$wW*L{S|Sx$sTZB66y`5qpd6H-z*0~okhdw;3QDJ;4@yQyt#(;5 ze9?S)ab>(ln+sP4>m7Doc&c0tc|2GBBcnu6jq7bH6;Oi<^@lU2Jop#15M&Lei^uPT zR^tjIdq^#PT!km!%Vu32f=I3mR~1z6y!y6g7_Bgm;iy|Clhc}lWu&AQq@=el?zFE1 zCReGrRKYmKLsYBC8d1_<$r{GxQkbTg5l(LB*s;9Usdn9 zz01R{OvnVL_J@WuTi2EAMI~Mo95_46!J$%=4Ud~ZS?X7Y6II3;P!9z5eV)&HiCaTd z^t)hvbz4Qw%bm>xmW}rJI%_y^dpQVowFi(_gjy|T7m3tN-EatX6Q$Hxb-~Q&a`^<8 zsUz+fM_|!v0(&u)T|}L3bZ8x57obwDegb}wJh#`?Z1NcEc{$n#^R=S~Y3_Z99>52{=PhXec+qn)6Ig_(QV~q_pVajU58@BGTFHtRFQ6|$#@P)F)3N1 zbgd~&CD85M$4G^v<3F7Ky=P)vy?^f2J%Mf82Y+V3p@uN}d=>&x^YbtWe=#DLBAC~S z7LOaD;(X5i9Opgv;kO`Ttl=Vk`}#Mli$DHhbtip*Tkj48D45<{-1+SbW7mLQ>sdUe z&$rp!e7)Wg--%*x&o_s=QEFmz-~Sucd4GL?diXt@#e2Kv))@k#863>u9?RVmgf~tc z`fSe~lbLFrD;#utJRY&ZQ5*3#3C*C!Q*)EwJ;;;<>5?jO- zuHW|e4-Ntwq|vYG()V&|WnZ31n;ICuCN6c}$+NLJ5Xm~jp%N_nx7(%hmh*+*?e!pG}Ixm)p|I$ zn0A8j35Ytd@&(zK?!@pp-;N9GL&O^}np(!s?&CDwbQ*TLg%(4g2X0zfOT8i)IBi*+C^NAG<&g=qVYC5$Iv2L$0LQ3yEvH&wi+e6y`k zws83jQfm~;y%m7zaQW|~lBJtqZ~`ULr5nT9c%fk2*!4Dq1V4Sua0rIx_^i^Kq&#Dm zRdd3VY5w0(7Ho;3i;qwM(LIyi+iPDf_xsVrSVc(eugwk$dF3C&B2JX3B8>ig+YiQ75z4{i%{f zi`^O%mYI-)>wYFG|cp%RJ zTTc0K@eyH|Q|ECxdVzVp+3*85-*bBG?0p%rroKGG3(z)&5q-1Mz%}-mNq-k&ikF?Z zQH0Qdg$gc#h;OK5kfY!{gpv?yQdrx?4oKj$^gUA3Xe3;kaME3*i1(+JEMT`6iBsfX zi!b0~7UW;FM@|0Z5IovA7f%d5+(~Jsr8FKMoUH2^t~lQ->z6}Pa{@eJ znlZ{&i~q5G4*DuoxX-O;Byphl_kW5+Z^8`o-xFHCPLFs!$QCC1bBAJ)#eQZdux9<< zWHS&sWc9qkd%|%%YhxDqK4I)79yilulE|CE5ev;MJVb#S6L9HG#R_nU!5L{Kaies$<>Y3k9tLU#Gi7Z1w?^6;mA z_n>iP`6z=P5JkrI#uvi&r@QM6aJc|mkQ(|i0Xuj?9^0qx+mM)K%4!<VUi$ zRw2Sny^uZFR1J0+kBweamI2ng1irI42t2yjQW3i%nc-WL>OA$B*TWX}RlkX7dBKb< zsI;prPGtr!t2!g6v0JNM(chReFU5e6t@S*K3l}$>#ESRW{P3jv%NbveW_;p<_v=F* z0F9SJWZnEoevO<5Tnd zKr={Sn?wF$%>2>}lUsm6R_+kZ@4Dh#t&c{@IN3@YEnRFy&(noRaRGuPpTFgw(3lw+ zoxZNPE3GYYItmv+&~`w8#wb*&r#4$V6@j+*8FZgJyxxhP5O)YoRV-_MI0^vVpDF&4 zeG5ObPf?EOk9=m&kL;Un`IqeL05hUe{zbEBmMlHfs$@=c%75$Mk)vtXXyt8$_gWE?2(y z1U{ziaIK&s)pit@pm)r(a_p|B9BzXB7S+LkN&zk2gTy4fVGhrYH1VJ}>0BHgqQ=Q5 z#Z1UxZ``e2RVa~IMxe||Vq8-*AO-!FuJ4v_I&}0jJ zPI=G&nI%A-S<}Pn-&f;+iY-N?OnL9@k9dS>9``Q;+q>_RNGK8%+jxTOt6l;G-(bV* z4IdN27-k@hPb*KLEGK8Tl15hvNn#NsZ?``XA31KEH2!7C`uq z=Zm%a@qE_s37P-$e4joaYuP8e9shW~I8BJ=2T}kTXp{Q`XH=WO9P^9+c)lTKS2{cd z9_at_d`#y5gXiP=KRute=3Wa5mdFCje|tXZ^g|s8VtdiBs9l5sOS`TDsh}VOn6c|% zQZnE0&cVOASNrjE@6->CncY-9Ql2TfYvrDqrS$SkTRy}`qf*zT!UVeR(H#AEXP#=L zp(-bNM{cn(rbIl|ecbnI^#Gk9Z;UXdtzVmlu>w1di@s`T(@$ewaZs+#F&2za?K3v@ z>4j}&)!j{#rafVVpa@2O*S`0qTnX$zN>N*G;nvSZw??b&sbbF4OyUeg>*q`0=pD7q zm|JVZ=TSz-xIE`@Jc9dC6qwIrX6;)$2pB7QFG_xm=@5l<&?&BgS}Qm?gS;6-yrNS` zib&F919*>cdXKq56fax7#6g$Cq;N2bxozKYM>@N$d?DNMRr^d35AkfK@Ik8dK``PQ zlFhDmecxCxo`f39=BRH4%iI0)GftE>LG9ihCsE`fVIgEvjd5e?*v z2a5M3$O97fuiFu0yK@2IB!HWgkGYJ8FYh9ji# zV^hLLo4L9b4_-r@RQvboV8EF^5Mu5kK?89|NY1ILm`60|(``m44ND|l7@h6fYkEfg z+=UQYT#=e^X*i7riS@GvBL3$j#4i$d(EsBk1UtdX`%h2FMYD(d-$x-}m~Mfn+bJvL zlb|qtl1Czyk>8HqjJREr6I06}?1l#vRRt()5-Q@%P{pRnW83R|d&lgnfj$nhx4hCf;qRulMp(uA$)R3b@qv_~74rQr8n%Ljj02{Id_!se zFc5$oGXKl*>Cd-a6Q=Z;Wl{e)K0(QOkf|=oD>v3JMMLHw5ON{P|)0LQ^T`)$f=oO3Ss887I}>Rc@cP+JuOpc(D%Y zeAH#xqx7(;E;Yv`U7hyhz1P}bhH65as)uvik_BAaKvr2n?t*LXj7-c4V>|FKG(Dh) z_+heLGb>+>iz4Dl#iySWJP#_tA$=}2?(jY{Zs8xQgz7Z3fIphB2simr#|liilUd*4}(?;iIm!g_M#@A?s&(Z{dS{ z3u@FGq|e(f33&N4D-29EQP1=+FhHsIXAk$rL!DdxN;}2bdhX%9wS&7!pE3uHkvUfb zkS#XSrvs#0+dn!k%2_G2BAQr!Y4Rs-uK$^G({1Bl3O(5n-~o-_7SfA)$f(IW zshx>6M1IU;*9sby@;n@W}p{c}2Lga@=ihOo&wG_!L$35r1c( z#Q*5uBe(tU{ylh-|LWg!^5bkldGRMPBa5uLR>od4wAJhl$5tekJ`>`!gHj|~H`8e! zrBTH$|cB;`Oe}A7+mol27quO)C93E*IAIQ12K#Jy#O?7E z-Rl0Pkt%|xVeU7r!ncOEe&mc8(&5yg3!*gDL)a37_YgGG&oMe_-+xVsxu>@ zL$@62p|N-G`xS-B%3BNngq<@lp#_a(n0%Iy>uk6d(OgaNTfVVB_H!Q1p>whrGqG&> zHsokAn!^yHFQz>j3MJX7pW2y z_>jt2iuL)l7!y@bC>hEYIb!Cgq(O*aIiuY@6+o1{3HS2y{yelSq!{|XzB(kW@A?|$ z&|#Q2x@E}ce0MiDMObeLVo%?=GyXse2(i`Q{B+VKZi}k&G6qCy#)uTJUo2A2_dnaP zvMcbR`E;NNllCD~2I4ilZWx}(o#%S`J3WU4|B@B1Xy&{DJbWyEC@9|TUwaBTbQoYL z+0oYZIP-FwB>xdzN6!wF4yA7l)Qpp1Y&C9$6eKe7KI^E3a#~Shk{h3bE!7kLsKIH7 z*{IL@ShEal8b2#*#B zt=bz}cN}sb##@u}z3uSA*1iE;JNk&HR(PO$Oh!u_K3%ei_qW6e!P~;QNb~VFj6iP@E z#5S~D0_GT4+m#mG0RR&%K9(YD(VSh74CXkdp#r7nQ4m_0kgAlg;X>r+hoAAVB@Zr( zV~@>3(367Xkri2-2}piIRa2TJ-O|AReAsoo#plGayVUt+8Ii*(r~&p z(75&0nM*&iO^CS@^pF>Ws=Gh`kfV{U?`emmX5J?PjEUl>ZgX=4jluAvw+!jw6pt4cYUxf*s z>k0_)FQZhWLc^DdK-GgpV6P1P#`z&P8Rx13&8kU{}8&- z;x_nsj6Rxgt~KRO>I!74E~;hddye3UlnijqOK_VA z=alh&fk}Rvu);*6f^{x6NcjX##eB#9NP%xbO+)bRjID=84kQCfiiW!Dl_Gj7fn0yi zCS%A@)gIV_v=F$Qe`gTnex#;h!I)qpUYUeCOCJ6mIQgwmlQ-o}4`j^(r{Y z`ZY)fvbQl|L;1-Z){y2KTP>s1Zx}pHddNW3mr7f(tTxL41;k;v2P7jobILoMHJ12X zl9Z|NFPyb*Z2xS%k1v?I7bH9sd_QCQE6MW=iIE`!ip4o9_%})211me4640o94!$V6 zC45ggN#^|-&j&GDumZ3iKO}=}eHecH%=~sV5dcHN?Ty12qlbFsK_r`j-QF4ZIMb)U zl>slVkAC6(51EzAwi1Z6r%j5M*&Cg-j)u_C)J_zSy&mf7Yp|ug+4roB9hSjbOLiYGku9SncgU!Wu$%0gE#&Z3 z6^m6=h01eJPe=vysl?Bauv_ol%!@b|d{@28OW*LPjCYuv9GLJYzCnN7in~M!m`!{u zAmWvg$N~y@B?*fr5s})$LOWS-oiG4zE&Xi7d-u1Eu1;Jfx!QzBz3$C3ZgZP;*U zMp0f-IP-FBtMFLpsYqji++n3Ka*!q94W$MpTPWV1pJFy>j+vLIGR~h3V^%-^Im_Fl z#!LZ1HFQ8bA*BnRJU(5xhe*_7@n5G&ATQvi+R}&|(}*y@%eTpH(}c^WD+sX;_azbP z*`*>UPX1W6H(&RinMq^mT4NEU^buXUmiR;P=&GOSJ;G`k{wvc$fKk>4yhqKWxA~Cg zwkv0@IpP+cQ54_Uw-n*9XmxLXRC*D7aH}7Kw9D$QdH||kT~EB4yzP> zve^@IAFXlc`NAV$*X#mgtCvo_it!jUe^oTHR5obeeo1Pxun$qm!&Eb^vnJojfUIdY zt3z`mDPm=GsE)8>ogG0EZLb+(r9PDe2?sVFwe;*$2OcH+Khs6cON&gCq8A~QyX4i$ znpBf$s|#0MYEk^EU0{;a6v}On)e^7Cz)dovyjf<^vLXP*s6nTE>Mocf5t$vBz2Y{~ zJf^Z#;Dkl|lrWG|I%r^)+X3vTQ8nZs(Kx2U)lp!Wk?Ki;)vlMqSc#;j!-^O!HgxjG z3_CYr1lxR2DKH$0fl5D-jw<|K>1JsJq+4r&`)kjF8dnNY}R|AUT$gucW zv~3jb%h(ES0K!qRK^>|PAy+|hXGac|aVeG}G2npqa#2icvzJ&ibD%gn9~!@U^xSe+ zrtyfuvzGqt!w-d8rAvGnM0)Ey=O&@gI$riq9gWJ|)B&!?fH|r6v(GMuO-#BlnuJxE zClU~~>8Fi@!_jkx{xWnfx9nOPke5J~b4pboLJM?@ z7QW|@k!7~s3H<%O6Ei9(?z2i(1tfg9F$SWhtPr;AF`4i8c?{v`Io^S5f1MR^{;^D#TzC&n0| zl7U#UTU=b9xk{Lz!p3ys$OI~i zx`{Iz=GQN)8<||ZKo6Q##T5U0KD@Ct9=m@L@}!SqB?*KjTvdJxU0&Q(FTD*_z-z_R zSEx3*PY!f;gnV9K))bXsrW?keerGg1|Nb(aq3WzxlFUy~7CxlUJ+*Kw5b@sN^oWlD$d7P$QFtZ zjk$*APKo)c+z{DoEsOKu&4;?QaAbx8dDY?UnysC4X5w$5)3A z;`&b3F0bGEd*@jXF_GYZ50q%5WHEO#Pp`Qnd+xnJBi39?k20s{xDrgXg?_Hfc7BKP7El$ z(WKLWH9JSIbMGQL8(%s$v1_7bhLX8sShjP+PdZu5be5`Nis|Xu_6>Y;z4a=P5*gqE zLzpOeb_GEPUq43h;+T?4p>C*JKc*IkEq-Cf)Q;RS zRjy-?M=@@#1P9J&C4Fnn$w*DvN4dO(d^#%{$l3n{FmbPd)5~6aKiL4(m1o1F_dJakrLA zM40Vv_coCpSD0tmq3|q_!Z7eFptsjR|22?|EU~Mx+2`TqaDF=?54#f|*Nw{=!7oPp z$Z@?|;LlMMtf(>k$7>Rrk~U`b77FJ>hYOI_*S7_#AWNdcM!NQ?apiv7Eo5l-`q4*AKlE9p`^eU&i0Oxt||?8V{z*K^s9SV42SL zaOmRdUN;!RG*y4c-HMu*L;Y@J>f2GBv$vsbZ7OqT*f4t+u&m}D9=2b8!_|<=j>)1R ziK=~%*}#wF3Aq}sea!3CzJ8_YC$jS;DZV_ku7FgTV*Vpyi+m+A zpe(VVNw}r`Yv`Xai?no~!#Z}UYKcXLyU)fxYVK^OUQhdoI_U}&%97nlnbLMqR>{Mb ztM)ItJ$jZojuTehB7S2;x2_Kczx$n6-S_uu7(VkX37&_VpPAl( zE!9G(dQq$&$8OGqERZCD)4?lWz{C1^+iit@Cyl7q{|Of5i^EQ^!E*vZcUHjixYD`C z!{hgt6$+3C(Vf8gR%dwz)2T~6Ct6v9s!x5hj1iqILGoHg8_O;_3CJ!f#K~P*=G(nX zJdUAvjfM|>SzTXU@~$K4Z#U)~(WIZ-%t+1j?udF6!6e{FMOkOShH6R?ps z(by_$m$wM$s7Xe~HP%CvQ)_}wj$n20Q8LEpuN{6ivKC#kR_6&41WE{Cja?=90yvO;Dn^HK}EL_yD$ zri(|@++N+;ER3 zoj$)}Sa^X3N$ZmZXfGRKjGC=Y%uIK=nnB7Ev=kS>b?WM>5kG;D2^BH=GfQ#hA}M#9 zf#%T0M2EhRiRyYVcvK->4o%jgvtXOyRB=i>>xfKfF_+tD)T^8!(usvQ3+Olu-6)&1 z=Ij<>>Dd5oDCjqJTsD@W>(vKm5;po_YP?HQwkQ+|4Up$636HM8fDT6U$LV(m#%Cz~ zhCv~+_p|S&qcrDxK+|mSU|UbT-!F;^p7KqVL#!Aq${-{n)2ZoZl3xulD80hO7}v4{ zM7}>6(BdiHuPxyH+79$+DvbvB)^XvRk2}U;#WtvlmJXz|{xU`?AH%^@S;yH9v4Fm8 zXI{k-8rf!+6#5dmgn&$Q;^rBNhTf*UtE!pvH%JNXUfm#Ul8p z@XH!r4^vh~*U_X%^)bo?Wl+h`v)E&V0}4fj>Jm*^B6r22G#xrNhJK|w9Y?ML$pn+I zg-wMjD0p6)VN$P1y#;zeS8!H`$;Ugc9JfSF<)sJ)Qb0JMTAi-o~1b5LCew7ttDMm`3FXMWd=|C5r3czCSioZ&S^ z(s&UrO`wqs3PGLt0d;rKsy%{GkE!J{4(}Nbg!0k@>0t*=2->0Sujs!U!I*GqiZ99h ztB@}~2F}afx?Kldbreza&bNm$c5Z$|xPrIyLY3NGC)5oXXQaS}sR&AvK3CylUV+C5 zfq|8^|0xDHB>K7H)f<0O#RyV1THz3@^cs3mQpS+jw;h1hLiC?Fh5atWpV*jnwzpS& z{jL0)QaVqbL(V!D=F4BB9m2cOE{yIyWzvBu)%RB{)i< z%HMPK2^RfP?4Ly=sN9qtA*(roEwt?`VfYa$H-mR;B1QN0LBi~ff1a}3OtL%%b%#+X z9PVX%BeI?UYak+IK%;7ly^u^na-;34Yyk|OIyrF^>TxBdD54DxSt$ggST#O2P_y@d z>541nj4H=arFzdq7|-14-gbvj#PAA8BGT(=S?Vy#_daV@n8(E`t3jNyq!7VL{Scun z@TJXT3r7t|Z-PdrIbe({6ThxAP-A^*kbNoe=?!V$VBNinShN?V7iPvy82>z={&dq_WyTqE?B4PXuD1U@mT`L+9nG>gjoAyNzkA)j&eI5C`mX=tXlkg|w8$K? zuDh=qSW6i(h)JrIm2(qz2|j6&Lr_T#NIUnB^?45Ubrt&hkbcf*O1SjH(EY39yO8Z< zc-)3d%y{kTu8%~LnSL?^rJ=L;jn+k%4P&2^nYR_^^(P4d1d-okAi%&~)ifarlVEJ% zv?hczqk(9nT+V=X+NEIdQ*Cu=D7qEwPRjw$?4a4CyEgKAI8+wLvfJzSM1#H4=#UDI zyWCZZ`v_Y^xjE52`(oVze?+grvt3*XlV8G&Qr)jC8xlE%dwh#oS81$lggfS93e;5S z+{(y=ukS-;bA9M>u#vSz-3e{cHMPH`c=$~@${oHQs|s}7p0Z3hUdRJ4ur+Q}77h^NYz8TwG}RE#=Xbw$sxx+C=g)8rE!v}Q~8vMQJ}@KUU$ zoDT8aPd`>Ir}dRJ8L5zXP#~o{$bDI&N0tJaHx`oV!=lmI$)&DlhvS01 z+k<6UMwVF&oM?$*;;aag^x8zW$u^N)IX&d*|$5EO4wBMh)ZHR@7Bd z*4nI!hI{ci@Q@?Ysg|o37mL-f0T+G;@~`UJlzxty7yIDBcBWTMhln-3%`W1?16Z5o zP+|IokfdvD2%Jx1WH&5cD3J({Z6Oftn~By9Gm^10vrKPD=ucj?2SvbV73_@+dwu62 zfy@**I;UoGq`R#bo52*NDY7%-7V)$5Jo95|th5fP23;r3pHI$d`K?bJH&Nf#-fv)v zUK`h_HvY-asZq80xw#Cz(QK;Kn0SApNhr6v`~dPEs}K;o)6GIy1x1C^Z7IaZYee^Y z{1Oujs5)yK5;wHTP*7XHO$z%oW2lYgofymrIusnDz*&$eh1D-6N3bqsF4qp!t4Yj;v>N<;_8_dPN(Lm(U|h_R7#hb z29zRvaCk;}n2&Ry4N|W6{m!?}RazMRY);kz%&uWKd^A#FAjZ*ApkoERXNF|zr4KAU z^Am!5#Of=O9);6GHT>NNvP1<6N|^vA!+>om2}w|=3iJcQ#icF0MFpkm@L-SDfy6h)|8o!1a%nKdjATmc4y90W10Li)!e0eB?1ZMi5IhW?K>Z zooVY94C^U3V6__u2dXrp>DMOZS`kvG7h@53#u*++f_15r%d_&-4S}!TGpqCp#UfmI z=>vA&(NF~l!2KQQ`FU|o@K`T%_rQPRv(fFN#bdDI`J*EYH4f{CFsCcMb!f?EoM!@O zaIWYGYzt=JfU&Tm%HULb-`2?0Zc=*$LFqq@XyjwIJg?(d&1tdid94NWR+CZ!a7j z8HvEa2LTCd*iD*KEpW`F;F+v2{Hp5;vh%A8w#83Xk)5>MK|3)s)4JN9V9R-6EutF5 zLnM6WHd#6tmwdlYC080QSZ*dg)}@E~<$fXb!PHx2O;#CD8Edv#BQp7{#j~usS@=By zQfLEbBvujBq82WgfV$iQlF_mXzX$tU_u|~r2A-*lr)!mDkH^}o6I)0UTZCt>LbTU_ z15e`#@Y+5y2naKCjMhh?uEBnGKe}sF8jBOJQ}VWt$4ShDviY^n7GxQB>z~eJ0TyQd zLkR^US-Jysivye)OSI1WZPiGjXN_7ec{Z#Av#~s^1GiR4p;yU?wU!UVhQxtYDKoA! zSkb7mKW)gMWwzy?uVFaIHr1k$->I(OTBiNVTGJ=QVYRiV!;8DXXh{`CG-80kBys2l z72LJZ&@N|8ro3qI4mjX|Mt^$tY|Ns}r6+xGs*>l%+SIT+{pPCe`4g#5i7anL9y5oS z7l@$ANY)dp$CWM*sv>ae4j@E_U$Neemb^pN!i*_LxcjkdnL&(;b}aYT3wn*U%_9;mY0^Q!}Hsal&pkAQ^UT_Vf4Tp8ptQ4 za+`u|%_(R>?h7qLwYSm+>K7hX{u;HqCB}wn18b!N#qhvo`+6(QhVE)=HM3EQz$!i< zg?lZT0v?$SxN2NEQM`CWI$#~Fue@e`q!QP+gxd6#wm6*tNHycjdc@iUggH#8KZuOB zK>=9!*z1n;r16ZchqgJWQmTN}D{1%DVsoS=pxA?2$HS(;KWv?})@e;w#>2~Ny<7qy zPu0hilLgsq*7Shuu1?K%w{C5V8%uQVcE^CSC2MP)BO3Yj*V}M%R96$@S?iZ(!B#)< z`yRKoVgptB=!n;H2+JxzP5D)*YP{}aU27f7A+>iUMr_xNQH!mc+Wv*LYT{nvjb*0B z$JstV-~B@%TM}Ulbk<%p*m9gff3AWK{th> z94S>iHsziFg+El;#MLx56-<)kueGWfY;!S5{=EL(ZN$-amX-bZybmW$O*V{~wF3-h zMjD71uIm(e;|L_W?7S&PB*+3!d8dnstGn*B?UOiltZQoeC66IMow|8^+zqwTuXzMN z^;&w~NN`9O=RHdQ;*nj_6lKOFuC+x9;f4k^81?(#=C@g9oG22zk8AHi(czVAvlk1e zvju3f3uhA4lVUa+(Yo7@TGHU+=_L?6X|(>B!rDusCy*UozapUrYT5*_jy$j_5sRzs$Ah&q zs%3oBINCUWI4Lp%8D(CSZa$3g3garUFcE91sm$U=WGpHm%T>ivEHA|{FgPcNeKLdL z1xd^Zhj)@!mn903>kKJ1M5U@0N`b4$HO#CKH%kcBt}MZ{sA@G`%HUE{oi&MJ@5Vqn znE(sF&j2`GzEaV_B4FL1c`Vv7w{$eE6nIlSk;^8UwnQA>h26kXH4GjU5$XqNx)4RH z6k?bsU9S25aY6I`d+Lu};jlK5v`Usv=Bi=hL$!I*fji(*aunN73>0PaJ9Dt_8>6g5 zp&%S#nFW;!r5^t%H^aOpo~UVRAgnrEILef+fEk(6S)fG0pro^cr$$O#)|MhhfO=6S z{yu9|ukZ=!Dcntl za+tuv6rkD~is*3LF3Reva!Jcyn%YAqN#uw1tl#^us`f-%d6n+eQahGYQgnmtYPs~F z?k7yeC&;xdtar!2O+#^iY=ubK^@)#JQ-R=hbE99}jFHvT_%_k|#lace6XgfUDRI;I zkfz|TlMzw-RpnM}XO7FVgT35Z+E{7IH~vX+oHa|-fxN^^`J-4#p5r61h*hUfY>b!s zSRmK;b`+M^xBQe>^Y{;Bm3Ef-LOP;HA2)rJx$s-fz9%&3TE_+0FWhDV?U%H zC~=O-?66&|b;&IY47{#?+kzx*%~TuDc67tONzFC47~EG7iRUje&sNANlKO9lER?kZ z3$NT-7e|}M45ev0g*V&Jrw#Wv(C`sEJXHLtt|F9|5!ekk1yyulgPGn0Nz0#kBcK03 z2&f=ajjW1J(%?19t3vMpYZxtxP8koS^F>Aa61lU156YsX(%ChY&sw;?xBNOuEiF+SYTU+VpU*g(#-0XpGPI{KegZ9P}vE*A)|*gXPNFfKQ?!>?BZ~&urv1qKQwkA0p4ddQv?o9ROAyUPu-q)DLeTk~epc1_VkU>q|6k z4KaM$i>4@wqMruGsQB&f4oIVwuFPM5pakNGctcEx zK7Pc813bKEb%W_A3B{~h)u0pA73L~ggUPd4pk@}$4lgz+2mWp-q}3;T~{ zrg9&~R?2avM9r*a9)1m?zs7AcY}=WJHTYdPebOfG{qMXE*V((;c$k^Q^uN@`6isfH zfeY8~d7VL`fAc!MPxXF^1~L}E|2wbKt@)q44$r@N9rnGG|4&{gADzqp4ke4Io!iUd zW+#~pinE(9=+nvmRkZFzaykAiy=lL19L9iW)h5`I&}`!5+YNEd29c+KXSbKV-Gt1_ ztf!9CoZ!aw?NeI-ZVaHtl4PH@V@p7*=hyDF5SJ4bkJjMTSazG=cB^|z+lvWgBVvt| z{<+4B#1-#Ig!Sa2lxS(x!Eq^BD{h6l#|$IzDZ;`WA%B6-=`&t9pWEl=Z9L^pX|nP$ z!E2P2ii{k7IeqO!H#5Q{Hs#h63@2$UPwPs+59@);R6NXnncJj(_Hcu1f;Ez0sWvyH*&wDwZCerMZa?!%XG80FGUH!w z&gz9O?EGB!Qpi**E#mrxvM$Adk15EHKYt05Q!j1F8o`JhN+->`jAF;jh<`O0S{L$8 zTBhNXMs?i<0zC%f%AC$JMDln|D}`@u`IIS}oejdaZb9Vi$nJYVtYTHLm<|Jw{*_Jx zMiX7`=h^Wq^v5>HjkEr_r`C*$n%4-P4Z;qp?k~7mjqtvlQ-;Y=tz{hNpgZB3x(FHD zZ=3R~-!|3IHUbUlZhg`(vqN#nge>%kn)s29VH&;cGrTXX%~Q|e4cI2vkiTk0$(wof z0ZkcJsTkF&^e??aEjwMySvh|a`+n)Tq$0JpYd9}sH>!ShkbzRR6l9x`NK5v*ridCZ z#G-*VlHuE{Kzo$2-vGOfQqVIRbufnS>l`t0{>r~iIryMQ2(nxGl3AmmbIiF(&f22A zT$H$RT_o7PD%kWT2H{wUDVvZ!Y9RSK_xa3}8FAqC0*ws@6?nat;njt`d@#^%5i?ic zabt5qGUVBzuTR}YAEfRM34v`Y@!a`xrA$bvgnjiY8A;~BKg`CT7vn{MRkV$o`!f=Pfs(MRn`$G%M%4> zuNKqQrJzAv!(wp0NS7*$LkUzp{U>kIu=k(5$(un!gEvlOigwy^AX(+n%q7Yr6wugc5M)9a-Od?P6}jxzaMg;7bvaDAlyR*jH{>Pm#xH?ph4 z$2AmB>H|Z(4BQ)(==u?oOHHZ5;TO`y-zuonIK}cT&a5%V7u?U!w8zm3rr8O^OknSU z>>&rgo-yo43lwQUV!!J6!V9^>Sjdh_^DLAvN= z&D3}pE@P3oEOE0Z)M-2*vG^m7N#C~d%e2K9#!|8A@(k!@>a-dqb}i8^@o7zu7wfRTXO%?keQ8&l|VkdlZx~%iHz^@4h zi?@-T(OhM#2I#=zsxXqZveT5pzEJJcnyv3g7Uva}LI=y6f8CLrE@h5i!CB|}i zsHHfLE%5}Uiy?Sr!12bVf34j2^dMxbF7R1rz##2%F|Q~!_7kot7Z3lS=Ct_lgb$hB^+T;o{)TvPiH1E201$JxI=mH`+@rQ(LR+?A=1`=@61ofqWxpvLEl3;~O zG_Av(`BF|TzTVZV#1?%qD#~6=Ca$V< z;ftWPuGL#d4|RrAlC`Fh5LZU}{iTR9DJGOP(03&Or)3vIQQ*@-ERHGik~s99-Rlqr z4U~U#`XLuGcEMp?{QaNZ^D3&COipOP&xd5#)62c@d}a~S9B`PwoYP1pB{Eu1D(fy9 zUzb)h=LcP(zLqw=Nk{}5YKBczlXV>b;Xx|QAOijrppJOmD!X4=arumhsiW~2etVdE z1vRC-O_-&+`MXMhr)){|?mX_ET5D!wRx?MMS=k)Emt_05j_8uwjPQX1VB}!JsOZ@F zoi8noj^3?Az_z&5hkCt;!QU753@~P5K=UJ^_R+v+rr z0{#5L5OE+`T3$|R+3Ckk`kQ(ROoP<4F2romFd91`Mi6V2N%3vx^aujrJfr?lCO~jH z!m*4Hu~n{w&YMw+Y+zX^G-NKA?#qD$!W3whVGDvpG6Y!>D~&Z&1KRtfV`TsA#|A7( z|HzuLhFNX2`oMnC(4*N*RgPYq1!W$9yVjJGTl@a_AO`Z#_V&v7!T?sE# zEREgB=pA+LcmM5>W%=yZ7<@N;(PnxnA3DP%iT=pGC}{D;HZBML#}|V|$FVqxfl@?T z?;bWZ=A0kC5R}>tt-Zxd_W1PTeBB-3zq)Vc+kbT5CmqSP7VRHmzrTcnDtGROk;%od zY5@7Rr_bci4$XeF*&n-26_KQ;&pp^E>&#w;j+DB-5s4neFE0hOVQd`Ie_B=mK_`ka zBL`*j5N%vje5?>Q1>4i$FRc*58zFpTyQG_%OHeogHz)igvpXs9A$ZQ2vrPf#)*;Wf zuzuG&`t-MMAAIj6+Cc?0M~{42l>n;)93S^RQA%KfyAvSXOw*7}CxXh6O|C=;%vLzT zzv?EfcPz7j1S&E<^4K0Z&2Z)ARwOmxh_H_umU!(O7OZgB+2cSfkjw_nbRQ~$5Fr09 zNU^E;!%gA-{goKYQA1j13aM)UdCjGc4I4OHrVJY2{oO3C-v0nxq+}T$6q36z2>onW zH=N~|8#kp1RmQGJ?#Iw0Lb)YA%^N$?Qoh~JC7L|k;Tb8NbVg|;5%?=m7-D4DVs}4bs< zAIkHiE5N>2Tn++;Zbo=Z;gC%UbdM{l($H+MGoI1gF@Tk}x%{|ctAu6(@eNsZyP$Xr zt?WF!xwXlb19>fWjSt#L5X7Swk^tY6%6Vcij!hVj?{HbwYOVAcd~Y5Q(#(^N_U+3~ zP>!dBg)mw$uB6iKK{ZhujKKO;O_{AdQ<$Yp9 zsR4#{;kZV(1kt)U!Xc<3UMbNi+q6qe1D^#y#!20HJx$Jh;YTJ@VH!p1CG}6dg}9oN zE*{QAfoPB=78<9tBkT>Nf{e-VoJihk$L6rnTZUiq7V1) zs8MpLBH|A{o&s8{e^H~TuP|lOv&R0D%X*Q3Z)E8R>;4RfY;lO~D`*SPxf=PglZqG~ zVhh%2548;>G@VT@vaTN>!e{(^fC zYWi(Ee%*~8xI!{xGE(*X_#@?6%9H4b(j}W7d(CJ5bqI$)Pt%$1mBHQEA};^%M#qlA zN&NBBPCs_D(Tpe(!{H`!w6TfOo?#7&nLF$to4SNwL97lWb0djx!;pVrh*ACPA&PDwGi2$1=G*fB&bMXj8i$)uixNbrbTe5dAXn?25dBIGhM1s-f?Qte zCdXrQRt|oO%t9n?RYGWPHoD#*!^gdk--&DbiMrZ*iX0?N&VE#`%#g3h?!g@-yDj0u zYedgBv?EN}ox@D<+HfJkcjZ3gN!)ky1-TNmrTZ`O)HC^=c>2%@K7({FWlxn>%TRj( zPc|k9BPk$;LB8}>`wF_ll3FecHJJZbA^)u5D|G?PK{|j-plRb3RI$c(SdiVj@{?^!GbhEO+)BVrZ)P ztR%zbtEG(pu~SU>7kH|fgfWa|YQ0Sj@^KW@Re#ou_xw@+9rtl!Zm^`)BzcE1LP+;0X8J+FVqWq%>btT%6@@hXK)SlMtQ*IXCGj z*Ld0_HRP~~#6-=-chR)@ZUK%WQo3O%1K2uIYe%XiVW3E>GEEgFBGf{xVfHql;oRJ# z?qPOy?mxU!B{<&oX()j4U*4%8FHg+cpTK;$zNnN}XP|HoAx=j13n3E37#HqP>XL^y@6I$G>9hlFG&s!7lA>QLLAyvmdaoDdn z^6-=+OGUY#N&BeAe^}IXUJptl%sOMdVzNR=lBvLpcR~qxQlw2?(#b5dG@9u9-&jCa zC*a0?IppFba64Fo=tG6Zc1cS|w$Q(k30^UWeCUB+$hiP&3^?e$XO z2oh!B;qyD|6i`CO9Gr99nTXo&x1 zoqoz@Cu8gnQl9l+Ds=dNROr48?cKdua6SNn8K#cG&DX;l;+ej86T0VL6FQ;Sy9pgj zVgvitoanHOk@M3`zE`0tWY3jlyHrLMQ5=v>D~kVEWDS?}XGo@zPaubEWyw|<{9~#A zAoJBe}wC=^<#=D!SOE?=56oIktB*B0AsdI?k2gCldhGYEGAbP_^dQ71_#i$pt`LP$)L98Ps$*?C0zGhvY6l>58=_BpyyXYCe z(ZmF+%vxsuQ2c@xXXeiU#Y)D&8iY-aV77Kf;20JdOrLc})OC3hATZ>U+zl&P`|aut z29-kpOn41KhcSx&C~2QGOtg{%-w2a|K+1T=+!*FZ9sK6dgY(>&&`&q{GT}1QJn1}@ zAA#AWbL8OMa5=1)Kz7%D?L2B!PJLwTzO;9{xlmK`V!tnhagMa2o$jNTyJUoY(v|^s za$jX6smce#q>vWrV)cd`ZnxPV_%wo*%C2ZLxa};xEyM!TZ38VAbM(mgQ>(tnuU$SM z5qRs0=r@K4qMn|8L-^xD!kWY9ln7SXQpVg!p(AAn@%T1-%stb}I<0b;^gg+=2oWUp2Zj%mwdS3FRZ^H&|Hqn#%~x6O{jug9@_P%@ z1N17CV_{97I%r&?HK6seNqY#=Rk-?_XwdEXLo$w6&VUR=D z(t!go7E=-piHKYq_j52i|2FOQeNN}R_mF0!Vf@tpW~2viVNM`pA^B0n6aBl25{wiL z5m365SBH|$`G>7AxUbGOyQr%H$MFtC1C01`in%D>2)^W;QBM^vHDDlE2@+~yc|=xj zm{0W7Xh;>mQUwEK4_sfWQQ8HfD)Up$B6x4zgi#fk=#Y@9{uI@h$rq0fn$^%Io-Yr? ziQ^qoAI=8~>~*4O2g)r6qSrS@<93Wlj3VSdHJzDbL{2PfA%U02ZT0)76?a?&GH==O zESYKLrxlmFnIxK-9ZkNxv%^JYA2deDq=Srz@+Oyhy{=jI&*8JAgDJ3ZeTv>I6}^id ze@x~iKfEcE0qO)-)gQrLh1TJ_1}`L0*oWeR#@Dj=Joq#S-a>kO+AJ}dhmt&qP~O=R zlrsy=6uQZG{G&(j>v_=^4uG%2QRvu8TZ2PWs_Vf6%grvEUT4KMI}lNibz@^9?r_Oq zasSYcbvX{xFs3!de^mLW)b6d{|5fGlD`Cf}DzQh5WLj|ot&n|Tk^Zf2b)lFgnGfbh zXiI6_YiBA4nifC!yj5PIi=Vfi_+Ay3(=DDm^q5qSxN$%($hVCPkufy*ye^Fnt>7Q{ zti(Gbb+ESEwh=iv*1TT6U&ELUpi_W%>y7^0tDIiA zvVr5FlQy6)s+Vyex`}-k^@LRnlk|tuCqjQW=#|9FH=ZRfuErVIC2B%2t?!;~g0L|^ zx~1~uOy1b3wyCF99iaYeoh1i1@QVx88nyUB9@V6S~;yMO>zaX=%rG*6fMxg}u z&u^hsQe#l>z&n7;Xql8CyneKFkles^H-3qeV3H2zXct1J zx@<^vD0ryeSs|+v{U&8)10SEt)ReY{kx%|cw>qC{YAzdzX8@n_M)eT7$Sc?Z5{wGx^~vQ;PAuEmm070sO$Um2hOn2q5OxNulnKUhZSXc zI3g8KRIdSIm3ya zb$$25<~MdlPU}LarLIA;f0y|+;QGq-^{;5+;on5I3@B;m6}M*ki%4@CZy!;i0~#%m znih9lHwjeD%TE#Ovk6_0%Iir&?cPwANlSpfp91SrN1KTA#*1L;qOFTi^f(P(hGd0(FQXID$RmtPl%m?t;25E^DT z0$u#=JO?kB-kyHnagA|lW$wcxQz#El1*8>l zW$*Xw4wOvCr-_uz-8%t;5KQt@dIE`;q9m|;bSTRU9R6>fa> z^y1!sv!(M-e|3J0a+C1xcL`G*{+~j9AX8x>^f}XyP(RD{U!nf`5bFOS)FU%zgKNHC zf6W5p9RJs-2XFbWQEwljuUZ zlSuw=qaLL6|2FE~>3)oQx9fyo5@KeVADmHA+H?XuEN1mUS`38@t_ln}4->Hutw|FP z6ATsyc_$ivJ+ID3pAUxzBS|kBCuV8WLy{+t`(GCiRS!`whby(yV;_Fp0H^P7mzBFw zl?28sV{kFSFk^tb6e7z=@0R#!Vy$#L)Gz78$`mfeUKQF?Z zZ&kAc;UFKN1i;Z!72A89-^3%}Xs+tS&rz41D|FFp;>_>-8*!x1a1jnIc?Y1usQYF8 z;)kv{{SBK}H6Zf#1voOB1zdeI0;uZ&jUxnNXfZM`38Vl)K|artRX~J<{#OsJhp*#y z`$Mgmw`d=(aUY@?VYY@KVPLsCctR5t!pF}Cgo{he_Zvoq1bIu8%wB%Ry%_#asXfML-52~4S!hi3FA8zw~ z@bSHg>t%a-HFGLhy^A=(v3#4H4@i;kUwZ@$MGfS|slDB#rOnX)uUj;c53rYr&-*Q; zGLPy4$wI)DKq{Tg#zp7?^L?JtFOfXMzjx7Sw)O|%AO5q5-FHkh)8Gr}bHRw=`&xVx zD!F>r5UOX;;&2EkCAnuhIM_P@WP%rGdYftknv=;ZVO?*E*GsIgZ6V}>+@f!0=Cr@} z!&W_jxBu7lA;VC^l$);c_B_&{_$VRNQi|PY=MKj9XM)=;C*ay|@5O>C$5Yh&DUrx@ zYgqsSRwS*9M?ObnZenNn2|^0$Jvg67Pd>0ap69$-^7MtPdU^DX?f&|hp&&Oc&frkK zvN`ZW+Wb#D2hzcrGzRhr#S^uWpv}-9?Mk@fku9kF0Ct$jNl+Po?t|pXQ|IdAzB%btSV% zFpl;4I4KFp+k?iaO?|NI1t)YkIAq6PB$e|%s3vqzWzZTWwOR={dHH?xTX~V(Swqzr zb`TE-Rd~_dW!oi2xWa8xFk%C-(EJ$uK?$txmU zto@!F9k8P66+0ha?p%?CS3F5^eV=p;I|mz#6FdT=ZCwH}%BhvPbyLZE5KLgLn6iaP zQ(!4ZV<^+pAEx_Zc1W@HTRTDrA)QMrWBo2=1-lE*_qm|W*5K#g8@d1j3P!0-BGut7x6L1+R-{71#6lbSw?jFXW zvHPbfXBtF|bps{|;^C${tYBdt1oV}|NmH`14R4W1+)y{axeYe}bCI*4ol$D~5?3JT zJQ8H@ej~rR`fpNKZ-1jdrXWVp@h1JZP>aP7fq!B$N$1l42#h8Xw%SFDQ1g#U?G`0- z1t=liXAXt%`E$a7JQ#5e)op*8<{bBhepOjNAEmq&#&EDMy5GCt?sxua#ixO1gOAl2 zHU}di$21WU4UE4W$KM`MnSN6%|7yIsRWwpkuZ!~(GQAAWoJi$G?v68&13Rcmt6L)E zCxJjrgQ?jxyN1X^ z@mPt-FwzmsyA{hpBtOOxpol72hs>V2LZ^M;i2{y!eR&7gVUP%V_U}m@+&eob_sG4* zJ6V!7%NzOS=0%ZlH(S_P>iXA!42VZ|b~_yztl*#PQ33;#=0X3tda3jt5R|lSABXHm zy(<1nn{=b|RobIKm^vqJ^O>%m5LNM6bPdhn%dC;;(^R4NG#=<#)AK8m)>rz}{UOgJ?HBBs+TvlU%o_!wqCL@2t=x8gu;DlX z+JIL(=+>FxXQ3KPrzl)rjGl94!kLQ{eX;k-C-6PwP@CO5)ndfdH3|6=-RZd`C^E{` z`Z;e-AgdEAfIdCe2!=evKcy8#G1a<(#Yvf-k>(=7StY}=Or3q54!j}rmtre%+{Il|39L~&3VEi1oP>TiT_58%6rAbNVt_*s?v%Dkaven=7g0xHEw2~qh zau6^9OcgEQUr8O#g@uG^seWhUZJ*T2wd#B7%Bf2;IDah|+q7vg!&4^3X7wYB{EPeZ zUbSAQB2xBJ)YR0g64{g3OR#29jwF4DU~HDJpcDbfi*wlzdG;@&%>ptfegU9i9DoIx zT*r^N<;Zy@C0_ud-sk=NHGn3U<^vI;>-gTU%m0tYGvGAsL~!F_r^@~E&CcuF%i^R5 zGH64*DcvgwxYedpwPCA?fR{v83dXt5s20;4)JJj|dnMuP9~gC>P+y~2^`8Q)#Q^^9*DS%}EU>;-f=+w<{W9ca?3Cg~x`ZQ2iHI~2^}Eb`$9kzzFWdF`AqI?%u!h=W~(uODw=tF;O46x(qDhjPGnK!k=CL$|-)0zex1*DO;H7DR9Fm3=ulb z&5uJjIM_|%rLRe{GEVA(DKnQ4&wT;3OL&vF*J@y3+lLJs5L^@dkp#Y}%jdgENfyVp z=lAezLA|~sJqQ(KFa6UC*eOdjoa-I3hrVq)8H;R0ECD$N=FjHy{<>U1OQh~alpL7K z?FTLRlE`h3$>5hj2#G6D-R)^^-&rn2=SEQWL%`GOp>{koh%GyzoTD@sHJ<8MDN zn^Ds7NurNH)`VsOI+CknGafL=b`%%Q^wK~{$QghaDoW@_MX1VWh*hH& zmijggPep!MXFa5>-la8I(}xYt;Ci{{Y`8J!hu&-W&_5+bbEsrGJG<~tli&eE4h%y& z0tpOFek6L|Qv|_VNB~R`?z!x6F;oyU@x@V@b|T~YgVbs`R55_V-DeT`LJbtrqYPj5 zu{VKft}YsMA68jAko;vO`Q75>v(@=;Tede$2(D(OXbRz!QH9Rs1^I+x`!Lj+Yc0*H z7;Xi09_25L+EFu=g}ti@#ao88LaTpV25UBBg{Bw|95NFWHIZmRl$a#+zC2kiXg3); z_mKIaq&Z)5d9@cR5>oJ0{JBBUxo5aJ&%JG56b$|==`!HWDzKOmXHWrZrw~c<8LuHi ze44l_05l3pCc&*XS8yc^X+DI!IzATM^*vpw+GFz5p*=B6>uh48D(>WFhYZiX!@uT& z@TUP3#jI+3GogYT`l71!OU612#QbSkm%`VB8k&%eN>msjzaDItV$$}jCzh?VX#D%hFbY^6x_$(7a~lEL5Q<2RUpatpZ9b; zA+T%@)1eSaU#NmVpPV@;C76!4z2RMe&w5ea7cH_OU%s1WJ?;VM+nBV%WMKRsFXUw5 zHTYMs@JW7(Z1Mcncy2+MK^Pdrh1gD_d(w;#q%c;paxTPxd|u#k5;clpOM_beLN!pi z?_U!FD;0*AQ>b=?b z<2@uM$DWU*pZ<@rP>cahtQYcG=w7K6)X8e3aDXkoLjds4Hu1PYz`7kL{=$-;q?XtnG#qBvoVx~0Rtc9RFE}>B`ByFm+J@#xnYGD`%$zEVyO<}lyKikIJN7= zpRIHI;q=GFPSWV-EXl*CA+CEfqv=PZC)rT0=}Cw3Kgrss_j^%H7)nUNl6}r$(u>MO z7aDcO`XN!?Zq?z_YN3%4fy&{5kYE+45@7ZU{rwqOYVxjZU5jcN1-`Co7zhY00(ptb$XcTkMW5z+MsKM0 zE=OM7Tm}6)+uVN(AES)*Fq6+oXh* zq3Q_F=Z&_3lwNsEeuX5_2u1#zh22m%s8Tt{bEys<4g@piJdeC;G+U~650kDv%M$Tr z3z|KsND%^LN*HZ*q(d-b*zrB`FP~Pf-M17+*oe^$55b&0^+vvKhjA(Yt}~iGcPng$ z+gW4X_jFnO?PzwwMe66ru7My7g1gyA@e6m*IM5=grUK2?ZZ3IISl@_f%4LtRwUA6| zyMe412)Map8aK~6r170%O95qb1vCCHeCz!IFF(G-^C8qxrnV6Y*9z0vKK{6!e;99c zE(C$b=s|;4H_POX(46auFLR^^WDrltzl9_6Itzskodo24kaQ!gaRQ!KP0R^+I%i%0 z9h9tkFz2EycK052D=reY?udRjNj(D@uvSeMm&!;KQ1XYk_HU?rDyit*)JaqpIl3L5 zv}es-9fSy`!K@zxcLzY17^kEhXB8)M@34I@fw9_Th-h1eyzO|4PgtvOy zK4?TxOnS|5a@Y1yzWU<%PG+n#IiN`1$HdQT{XdgM%j3fV?(tn<9^WIydI#&zRq;-N zSyfjaWT6og)xN!LJ{E4wUqS>GsDYpx2kKh7`xe$dMObmq)P=_J!?Crs=yOv=QQP^< ze^kI&V$P)q2jL@Z)}<1!m9c>zw6VNs-#`hC#DOLQirJNFp$vU`+@QDprx2a>#nm~? zh4J#uSpE%#I_W!Pp6OVgpac6vT-`z9e4q0-oYfh0&|tx&e$qO#jCRne^XUHro&9&gA7EBjAspqjUVD`D^_!5sA+r1kYPN9C?>tZ^?5Z>y^h1(cup#_rgDC*( zJ`r2NoT~6eIj6cRr;}|vP+G)5*>IxSg%W4kl}LS68w&7~V#ngNApJE)<0rH3QqoZ$ z!@2X9c1gDJj>h#5+{B`3irqdr{)Bs`>3$6*-sfgl7cry`&^3P4T>MhCi6q4LUkS}& z6a>lC@xUoq3w0E>3jCP4VDYOIn&H8Vc$%Kox{#D$`pM&bjD$qcLu3;!g&WXXt6jl6 zPR|&|y&PDm6j*HJYe&S6NuO?W%^}oqEZ+N2qbb}!zAE}19Fr$xBU?J2;XwPhj6;w= z=baRKrO^B|=9#ru&~KK*eg@j<+G&6TN89^KSYuz=OB&&{!c2t!N2U~yMJ~fQ8?@m9 z6!*AzIluS|qv}gsqnEk)Rq#mWTA=;TELXOG&-$rAWes51-)I$I=?0+tF1IyUNFS8!lmaJXZMIZMfwz zXApIIx#b3LxOP?hDW~Wa{jbQ52Xc?p@ygGuwB5nnOO8h6Z}ybSeo|4bOu`iG&~i%3 zdat`A^orCTx?tITA+--og(RF7CIJzcU8zAK(Kd)0XyLwM8X5?>KSdzKNqg-_J6e-M zk=$e~?PK@gh*zqJyD;3e`a%03`Kz_d>1+rD6(FUhK7Kf!3rNr)2INr{09;m+2G{0N zDZ$|iSjTEbFl7(@Lqe{_gQ=dMxja^*$b!C!q*|I(f6{K2qa29kB-IzoTdpzVPf48-ly=fO=0z}0 z?O)L>tMsvhkc%(|3&OD<3c=^H+(Zjqy^8+aIqSs{&TKTUQB`IGOv9{T@_=Rp06wqx zLs1&zZ#S5dVT@OAH|l)PpRN3WFXw4L#xJDSWDJ-ctVBs^v%0f1wJdC8N}=353HL{g z30DV2Fj3YS^d%E1_qQIqP8~JgHx9(Zg;)yg^xXT(;-`oQ)n+~<(1_9?ga&u>4|k$u z@_vf8(RYqlU!Z@ztHb2dG{8_UN&+R6)FtDetPrJc(1;1-Dz3#&V&PDuB`Qk;8e;n7 zG?||7aqJfHuqE)*DWDS@Y4AYFLUFImq_GM3zhbUF;fOS!m>ihv22ctF3p;SvxkKnJ zV-i>|4w+YGwqbd&d0lBiweXsV*UI+~;EVkAw`>)mpOJ{EAN^j^cOH+K@15=RjtiWR z`>I&@s>xzV+EVsjPZ`hS9laeeS#hGkbz6(``2?=xlW0^vNTPUHJda)*B1qGX6&03) z4kPACjmIx3^1;j$qKf(yq+ma^^K-1vnB&plwD&&=)UNKZ^l|ywJaeRT{gE)Vl&%e9ygdsRfm<*<@i|YG-^cSE?j)%U6 zRn8=n2l30`DM}5IsXX5F6^e!2_|n0N;j38jCnGkx@=Ne_c^E={=a_KfpI-hA00$Og z_#~`8O>5Z%83Ze66Vs$y5-rGn{IcZ6bR+zmFn_s9p(ywKq+r9rpyOD2`{7#qQ#A_kBwegk2tI0K`bcs1fa;7EHN9fz zNsV97A4Kj7w6tmq!RK7tQBeTy4=%25_m8u!k3cR&MVjq_hxgB|wU3FPtqRlR5t47P zF0DeppTnf?4|n?ukUwVPPd%+?y@WdJNyfP$Ix?Zw+hRb!m#<)^r8t~dAlYdBtZkJ$QfUdr{*@{E2%wqZ<}JKHEw>-4Y0mKBIfqUZZFKeANQ$mrT)OTNGSszL*+m z)`BN_Fc;~Br+kz}fv5>c%2UMV8P{QEvqTtW?$66w!zziGeNB{qm2KU*wA1wU{AYO1 z)l_tAe2=oq4@jRHE5Nbr*MFwK-O349(7{}TFcq$T;ZY==SrIK77@{>!cbDeTeD_TL z#)7x)vj*(U?aft@t^r>5-yZa;0e0kZPXH~z&cYo4z0)?qt#rO#{S|S6p+NaxW$ViB z$z+vXo!GMvZ&SE$8Nxrs9x$pBle0@}y#8ud`f==PR6Amj+VhM-oc z6b8IVOz&!BE7+_1O>OrZFDEYTZ>b^%QCsD~!_7qrJ`uya*IUcVsg6FApKA%!FPj3rW5hlyqSbHVo;Sn4<<&9m)acZfI@^-S(R5Z zVY1Hn+3K^Xs6AjE@-7MlI*fN=2h&a7blVcUQ5X7*|$kyplhgnn$~t{<5Qdf)r`;jE#^< z1s$P&tDc%&%Rk}AM|jHNCJ{Gtl1h>e{$e4t+^EM%{AeH>J1QQh<1-sP+Ix8=qE(!H z(6XT9HBmYCIpuGzfYIVZSvMfFtnaPNuGQOh$rqs#>+%n3lL20Dc`Fxwk_YF42ZFV2O&KK=(0C(15qYc)1lk#n1K!SVMI*1 z3KKF1g^Z49oeA9WWV*89Ap~hS4W3Yh&-Nn=WnwsH+Xs9CuLWxyx|5PBWsAs?H(HWF z&{KpoYAHQ0M^;HCyy}c-w!oybQMyoJNJa6y3HJ6{pF)=caUU28rI}rlpK`*pg!1G0SA8e3@bZ$UcyP#Lx$$kX=Wk(t=i|%5dmfw73 zml3=7pJQ}TXayjA_|WSYMb>aM@mrtoomPYnClcoRv1aYU>T0N**7M<%J@E-RAG9p2OJ5J-e7WpQ5f z@_vSsyjZaypCnI1OyV^CInM$HGge9T)IR(CT3XABv+we-f2*CSYIIu*OMbOD9D2N9 zb5Cy|CX*T5ncn%lDQk=a%*RpQ$ze&a{f{Il;QhXFRMvAQnQ#g`jTn^`G%+Nva`rT~ zG!_`Gj;J13f~L6n9MX&;lvDqB-)Wt`)|>qLOf6S=EKh9w&^Q>|d0i5m z7SPT4+UXnPUW0cbg${}9x|tsHpmXo+c;%Dez*c=wit*gC>q2ub`h{7I`5`I% z80Uhymr2?G2dE9pv6N`PGwFrWZa3Wwn{DtxutJ`!?k`CZ!iD8lR8)yX){86D{WqWcU${n~H6~JFLFAj5xtdmqbnFt|K zM%X|bIk`e8wSwv(&rOXtFR%|?>?V;9JQBP>76YSkfp7!ug0#?pOd@J-RO6FiTgV&q zJQ;7aoeCDILIhdhzzjKqpRlbQj9JcAKys%7odzOWLdIzvhyX8J0FfshaM1^@quHre z-77S3z?@yXCPVGxp@{zTs5L-!i@*peeBYcf>Q=n<=n-@`-2-F@XaT?90B55BS=IEMmTrE`UGUe&!%o11-p9VrYr(o$YZ<%qxbXRO_ahwxB=P+XK zNQIp$AaEs9X1j|KA7Xsq7Uv(D{>2efq7|rs4h?dfN^Q7%Jl_!pCmfzwENsanc^_Gm;i+WP7PNjle z1slhy>8|Zq4JKc|JL1IOm@B>A9(uh=N$CMnJC(o)yRT%pH7lmR_lu5G} z&s?;^*GK+vklTPYz>s46w9Yk-?hS-Y=rCvCIiUyR0f~`^jtT8l4F?(@JVD;>>t;0m zsXz#MUJ$#2jV^$(^yLNcDcF7LRqQ5(9u9fsJ8(G61A=gwJB}-LrkGX15kB+x1Tu>8 zIKe#OiwTC{@;Vrd5Q-Zh0l}gGk;c(7X+y`g_$3_@psUyU_%{gmwM=qQB~W%{1(k(n zL21d9rl!*C_9Q5aEq_`In!rJrhUAX;psa=)F6H1O_9=8TXs-`Gr^bsZP*4@(LSc?t zAfKPGZM@-}-fS_Eny_26kLWJ2e^OPphu6;yf-T0mOoznT2Oe{WU~<^_qR9xJMEG~V z7T8!Gp<*ept+kEMQ=ZHVz$2cvrv3w<+r`Dx@B*kgtA7@>0(kK}_c*=@o^hwTLc$YO ze4U0wITRoMGuugT55r(Cn@i4;iqb;odk|?5O0_q+PVmW|57tfo6tx)LNI{A4^l-hu zd%OvXGfT_c)GF^<$4`ke2cEnT$2R0NGNWuO5zOq8HWhBb9Jy8 z%D5c_U|ZA7TIn#!Nx582QmFbvz_YBs+fq`8E{g7H`9sLf8M}qnK zXInM72_TO@@{z#vBD~3PhZBSa9oa~6@TtWYHI}*eo*p{}&~TTTD}=wKpzzePN*MJ) z8A(AT#5`_fQlu%NLr_`irugq6Z1Ycw6sK&Zv0>@ykGPRU7X^I0CmxrZ=5VX6L%tYZ zx1%hm-$<0YUyE*r2#qo26vFyp3J@uY8)SHm{N9&v;Tt|RH1N2FLJ}`OpyOgmA1uBh z*V=%_h>UrGdlZovE&@X+WW@&6NZ@=W%CxdyfxU_JiYq%Ich7mSJcyCK5Q^au{Q~F4 zh3d?<`)LrGjWbYZwD!3Ud|9tKP*ZUR)(9@dVR1mgn$0CPK`ILE!tYR%D((h6LEkGh zMcChh^->XUWv+O+*C=^Y)3cP0rN=S^)!HUG>JJ4h&%E)s6D@f-G`5o@B^glgxIS3I zZ`h(%6eJ5&3ujS1w(G#+qSKJLaXs=ItgQDNP}R8}HJw2Gsp5imq-LBUEFMwn?&cyU z>L>GhzHdJGV+^RUzI$#W!Vi6)dPidx7lqgZ;N*fVvd>{2Y6l(SWIP~e9}zt>&qtUk zJq11eyt&%nKX%VS4rihi2^D7`(#-7pu(Dr4zN@+w|D`J>3X_qnk6MTS;f zbp71j&WMQTpccae?)CeH-?)gS_zlRqA70WlC~p)4pq~5%kh}2#97?5K#5(o4%AKk5IEphEXODo2`LJgSa{t}1PX<=B7vR6aFFa7qRZlSpy2_Sa{uo zy*ShwQyl`JPF#WW3vr(a`guIvx1R&v-r8dTx?@IPg3Evh=TAY|ml6A=7q)bTZsN%U zm47HMkm~zC>903(kBGQFl0donF|#p0BU`E^EWfemgmv22>*4yGfwmNkjPxX7^cKb} zjgquaHtd`m{;_*Yon&{p*%zWu8yzY;@8i;{<%2@rVv64`9?>^|f8>Lqm%VDNAZRQK zP!sT)jM~)KTlP$3O$hzuTMoLVC~Z>FpMEL<&e-BYnv!(*k#n|Wa(9B0)N+SyHXf=A z1Ff)Eb~*!So$^%YUWGeB+Icq(!6yrB%MfU3-Ml9gAl${nJLd>T;Ryv`(R+E;_ zqc;+1_7|F3QxI%+?ZVU*f+Gb7IvuNvOQ0~;xJe(F1+$m?4$%1LrIYB63uXuf0ybs; zRgqq2eElLwt{#YcG|@IelktbXI5tP%8Hj=D-K*LjZ1u#iXT+wB!gqNkpGOWd__&f(L`l*TFc)l% zoXCQ?+n$?pw0Og3ARvdwk=IoS#p_XlX;~|j@Ie%?rfh!7fKnMw0X@@8rwZYYc7!D8 zv9Mu%a5}l^vf+L~a(2Ycgb!k(57|&bn06izm>LMwm=&vV}TUC&#}EAo@D)UMh7U#b(J_}@#ugF6738HQ4yfBoQc zZ|=|d2w!bRbjhjB{%*OxJ{SzfI;kNVrcw~aCNu7wu{dA(fBeMjf`0u%@V@)k=^w#H zqQq?&xmFFwX?8UZS$0NDCyC~wc{!I`xmov0DA<2lzIjh<#SU7EiLRvP{v0L?M(1MC z=4mn-4y1;{grBUtog?feD?>i6y@^wR)7`1N^0t*XM(po)7;_*#kV{1!Adyx`=BvMg zi9DqwcudRKoaiB}eM4}paFC`U63%FZ&Y5ef(Vs5OK_m49l!Fk&4KD^UEFly*5T@n; zH^%}weS>u7CA24#z;O2`r~`B(&nP9DDr-mc`R}DI+3z380bZPmY(9@DUk8G>?Qvile zlIC^rYz8>e9YFDg|$Z1a@eswKL*2yxaL8L8`tpd1FOb+&n6|VwyQH9!e z$V41-0-0+%pS~sY&EX(gbu;|{qVXR{ChnW0#b$Fl6imzK1_#-E#Y*X~CEzGEYW+Ml`cOb!-D1A6>IGhn}W)39`4g)Z|;$DblT!wIa} zrm!PKFGgB&u<~JzNtZwHSCqZHh0N?{Qc@lms*v#!V_!A03Kji!XFORSQ_~%Et;i_d z{csdZPtWtPt^%q)iwsP#xQy{Mg%`=1(PVmog^uv83$yG;)~+`z(F=CxGg6AUU_Tm8LKLqPI4L%{sV zO98Z0{D(NRA-86KBu(CbrAh6Xsaf{7MC-l z1PWN>LKa?3eiC!h5p0eiIdi&h(Cd=n8a}KJKDqEINm0n*H}VPTbuH`$YTK?MjgGt~ z(qqLwxJluQzW1be4%B0g=!d#z=ajjcx~eS$D=(#EfT2AiIB^eQ^BxwA4-A^RrfgR9 zu2P|nJQ$KXKjkfvjnqJHO@BO@Z&zlX)_RE-91ckrjh9a?@jnMBRUL?lj zpOvKD`}2dfFUV|z97tu*-@QJ=>)~A*j1}*J~4l*B>&4pU+l@Ha#&Lqx0cnXy9 zHcCeDjG>PW!9Thgwzh%}*FyP)9&E=uvss}2_ehgHiPD=MLcT0!pMuv{8Y0BQu=W9? zRd9DV@69)q<9k8IistW0hw1TqAnr%@;YbKes;Od?X&zG72Sa654=-l##6WP&PH+pd-gw!Vij7^g#3u#56 ztD=Or<>>+}7MUnkd_)aZHvf=}(%?Kg$}38}?u z@~kSj^r+OEpI}$_D^${oaAayo6y}I$OKEhIfg}IP;Xr#LM>HWNzQ;}%^X3=Q^RTl{ z{NY5-8zeyuub}&ym#+}&a|q<@wQ=C1WSb?T|#3|5EMiJ`U z!j;48Ubz5mc?hvpDR=O}NhNm9O_%=wXc(Hw_+k*78Dz~(ci&E-?tOa30iTT0=LE9= zImYm3>1@|5cERVQ_7xYo@dj^xj(9ym?{N}dlIDKDWD$D==sqAWdw|759CA1yu`3^R z;EJs0J25o`4SYYEt@xGyxn+lC{6ouCnCcLv48dSJm#?Uz(e0oQ#vVlZ$%naK0kn_y8E zcq@{Bo`G2Dj@W0&sMNa#(u)tjF>)caxRI|F+?YZ=&bQ{0%Z=4@-S%90FtaGi9bdC^ zE7+p(P{$jzVox*y8um?=^r+ygd_QKZg?fyzNPemG(SMYX_G$H)UUpwyCcF|NEY z$J8CIadii0E_YdoLP$_tGTHbkrbu>T7uf|?GLNrd>oqX=e{X#xlXw*K zBbC;2z!i5~Yft(DfwJb&#VI*_X05vh(!j*Y_)@kTu}jjy+h4O;p#mcOjXg-yhW&0N z=w3Ug*mq=h#M_(lOpvpgx@CVgf`e;7Gwaad$Q@`pXKcAX0m4I!#o~wH)HU&DX)3W7 z7yPa^WJIMA9lK%K$m3B`0eIo$)rV9-+V-tPI_5YY4!^0$*#d*SFd4k^3|qd3HiqEL@4u$xLH zLB|y&@S2wB0$kBR4nLr4wx?FOovuO zg?G5~pg0~Z&4SyZqwP=dnu!_1-E4s-F*a$hS2ID- z7+)scZoizazpzpm88wFjgt_Wi5}>4EsL8P7sBb!-sE!s4w&ROd3q_afL!#L)In&5> zlYnlI2&c<614B=gPwdXuIdj~Bor)KO8HQdS0|zd%GTku{L0xd@FA~`Tje%tZ0CiI= zffJZqz~;<_L9!Y*4xo|9ai7#8zpjxe{SFHh*AxW0#ZuNTWt%lg8=Y&H*q#Imy!Dp& zVC{A?5K~0YZ`T96W7MwM;);3`h>6cr)$$s}**Jl}ih{p-ik_h8^(!gK8iG8AsmYW^ z-AkkqOH44>tHNdUyoI8vKW=tq^6|p-yxLz^HeeAek)ZYd3P2466w{(JX)O0CW{Zuc z8af2PRTd;P^f@6|TC(Zwet}g3uc?dwcHB?hhqY*GG4#A^l~hPp9`Y`RxpK4iHr6zR zO6W}G`4Zywnd1GL0p*GI5r8{yRF><$E&siwN=?)^MqFCE`+|W6L87&Fw42;i1guJ; zZe;_EFKgNVK3h5b^j2Pe-1`!6GTfTl2nxkTCJ44I|7E8wdkPc9j}?mFHE@?am)0jK z|Cn*>ua2REa~UJ-5_*Dn?Ji#m+8oll!BmvlO;-J~KYaV@>c)X+c@LeIVib;!pb zjtjnoJb+x-79um*O%bFE6zg|Xj`%x9MEK=At&Y+>h`T(Q-gc~eXtW^nT`SnRv+TXaFrUwb&?vJSEUfM4pq&oXZy2kK*y_O9#|H%K0pX>x9_%XYflWfXnKkm(x z3WuL+cx8t9jcxu0{kM2?Uu&55O1X|7S7EPn6<=JZ@)=LoLXmqYtlVCp`c=<&N*a6Z+Il7*U5K0YFY=%+lBf`e_k9OATS-r}f%c*2E_ zP=;%}s9Mq?8?+9kh$a@_PdsD{KcB}-YW1|0N5mU2AGnlxr@9p>7S|-Usgd|tmd+Ss zAs|<(XZtRhqsHBmyZW=f5WY{nw`Od-a~gm)_x}NOK#RW~Y_jYK$IlZvs*te!Nhlvv z>z=aO%*e!bjyPzEKlHE)p3_a*P%O_V%4LXdTwu2^ZV(2iL@?3yJl#+f>sR?cmW%hkooXul~Si1$|&!ZR~sr$t+kpN z1e-uGkQ@UAlYQ)H4&heIIG4~=)=6W{iKQh1qV>R{&}c9iyNgfvkwP}3V)fSy05Ig@jtc z{jj@(J!+}KRzdcSxLcpL3JPCRp{EUqyG@ag60PdzmxOfUO?O~&Cg>83=xTks`gQ*= z#-%C}ARPt}02VbsBusgZ z=o3Z>kPQZGMtlH~M~$O!*`+M>C1vTYiR>gekRj&tGZ_K7{B{$J9?|6N&jpV+j?w2S zPm=6L&0>%#Ymotil)XN7()PA7JWlIC#c9*I&GHB>wNf0La`eAP0>jmILeb7QIkqBXCH6Jai%X^S8((v z4tHA3C4!z*X@ngMS(pOMgOnG50M`62t4w1I`SBkES=4CyG5`w)UfD8rq{4*x=y!RL zP}(UD5o*PTbR7;7l1d}hiIbHnkb{H;Tzgt%BM1>>VZQkwN8@p+PaoeZQH5znEZLc< zL^zVM`k2%$A!)L{!B2T%C}huh$EstNk|aLzDh`8WQIIkTWD$`xR5~6kjbgq-K^F;v)@&yjWZ${Iwh%qRm$CRMf3(RbB=13gTZS^RmD*jCVm(sz34w zPLIQyre1D_eB>4ggw>%cbZ1$3ljw{y6ij?Ah>Be8k`DQrD^d?nK zGs9Iez%ASK28*GX-+K9GG-VSqO=^WrADQc-tp*fXrs1qvlNnd_o3@i>naG;3j#V;@ z?O6cRufok_9_x_ZnAjkRxU-rHCw!jSh-{}HkD55mn)Yv86=$hzrGgE#9m*UPLt3~4cFJjnu~LNWHzOJ z8TsLC>^=@Ch#9^ohtW)*)$Dsk%Jkp|kr#lhqvtkzekplGRys}N2y%iqJ2tjpRrW_jJqV*P7HgRo2@8bE}?Wu9n@alF4fs)-FP1McY=>CMVTeUE5Gy z-bTHoRlCzJ!)bWQ^xT9M%xXy+CA4y(5?ebdO+TdiiLc9MjA@r&YwpC?nzK*rSP0Tv z7bBWUMZ%BCXoHYOzO!4nsocS0q#zobM*zX{17)HuU9w;v2&qr*@5XbN(6o}(YdH4Y zIW@iF1qjb5@}peeqAT7NN^OEkbX~x?DiIvzV;EyM!aE$|W~7T3_>+GD{~4|m zP*8;R0Ww@lG7#-Nf;;oW1HuITyJ>vJ2$^O06HIL&z1veI96os}K*>jDr6fHjrhO16 zcVYvAvEZQi5uJlSK773Rf6q>@2IsGT9Pj|?gFirmA|emIrPBT>WGl>erb$KkVqh1HG?dIwsv-GK?{SE%#>oJ7R z!Hdq({@dMmyT|)4Iv5MQ^WyOM=r=CsLsoRaDIn}V8I#?qo@E6_P)a$Vpd@JUUq-lH z{ng>#E+w?5UmO$X<-5c8Z_O70VmaV=e<_(Qdc8+b2Cr%t=h+mQD+Y|e(!t_Cyh^?x zqqMcWNj~jkTyoT8jwYby#5rZAuDi5J zQPDQuxT&c)PfGc{s=&o6YJ5{QzDY|5?^0QSbyx!qE#`2zzq|pp7qjk7E;CBU6IfC| z(ZwCqL(k~wB>kt62+}Q&qwW2A^w*=~{nx*3OA-SDdb@l4=kD=g_uak-b);5M7gtbM zte{})%e8D%_Co#Gm%+R^h1%QKM;wOJ=>o4Zj8N9SkP*tZtCrcpo1^31H+%bf1yisl zj~A?rVx=c#MWV<{GWD|o73DIyluzhhIMN7;sZwBd&#grrA+_R(8uSs(voYFB=tg9( zhX~{VG;A(-`)dDx9iD~v*=5QarErRXooKf0^+Jo!94bBs6mWf@6UE`KVw|=p6LA0^ zujIFH1tChWaAd=!RSbNHGI!Puvb1z?Q*2n;oLi&4)#f~UUb|hf{uXcQdlQ-@-^Ias z7k@|#n~_#hMg#7M=#HfVKB!DgWlACx2QXnRqD9tEa#V10{ZeKZ8IqJhkeo&_ezWNW zLy53gLPuFNIfqRWvPv0Fm%?@`doI-&JSjcp&?6jRC&e?@p)R40f0%svB`-^<{*PR! z%7a6_5y!typi5ZJ43%@lI?-T6uq%<@I66hS1})4gMl(h(5^bA9l*#tu=)-Y5<1Q8! zXf*Mg(ZtJy#>44kJe`n5o~=Tm+}q;3)IR5X|L&E@D1BRxS!-G!46_0ep&)R%tWG&& zW8hq(+DcKhgG|9WvLntiRJKSi?yk;yu+q#nQ4WkudhK-74Bu9>@7&zfq zlqzB_);jLDpx8(M{!JSU%9SCz?QCH5tRY1v*>->wu!m!+*47pj8i>C)#XX&K@%v%e zaliuf^zq|*mvQc(3XI!`vsIiL^i!J6Q{Vlfl_m1c%EZsKIniRI=^jjTw?0QRLIWq? zBaH`}Od06O*pUvKDt?rRR^i`yBYna!ou#HmgH+zFeQb{_sv`EiHqQCWO^GfPbk$y= z|M8G&A(%jLmsMK|gJP%x(vU7amctBTc>TmPMO#2DRPDh9_wB>++>evT5yst3zn?huG+4XRawg@p2BVke?QSti>b1d zZNGn37S0$EkOlUTh1Y~<7Fa>*XiN6g$>SA2STCZ0z#*EawPxvss*AikxBZJsMxSPtUFRzEX$6f_ zG8=?+T%lB*bwbRCa_5DE`I>jxDX%TNqy>{wC{u$8=Md3eNHK&2w{ju^1SBXqx%SFl z@8~bDy3!QAknPz(k%>l5&oD0n-Q0q6;ZCHGfF=oBHij%X^|1w|FfqdZyH(bWd_3IZe04bzo3rExX`E)?$Q;EfJitzY}?8=TiF?VONvv&jLCc}BCUV((t#k5@0 zf>95@7dwm(O|9CW=c9Np!S0+)z&5{i48pcean(dl=YAsn&Jr{q!ih*|-qqQ{=E6-V zk?@=-G7_5wbC%&Vn;(ReBspiKt3sSehE^L>Mmps=k%RKa<{&wxcTa5Zo zGMMHTeU%|fq>EZH8O^h+8VQvbAQiguv3#fJ6$KWT14K&;GlAtr0C(&n4_%X=4PMosP zed?1ui9f;HpMG*q_Ck~W^zrq~_K8SV-|cg@`dTuso#5Uf5cxF{pB)F@H!wp*FnBz& zKG&r~3%u;-P>WMh$#4!&yD!T7LZ4h?z8c%;hE@6+M;=`6!R zyoSvX<_e>FVwig`&@Gz?L?x5N$_~~JMwS^_JNxiuY7VzZH#KcruhRnG;>_eZk31xd zj_AnJIa}fxq-0Lhk#S>H0Oc(pyGZ4!CO)11y`x+#%?&CFj;9`Roa~D=&j5zz;FAUmW_0P>x;j%GH1?z zzdrxTrxt9|@8!);JY1b|`*Z)z``1-BFNI5{K0RC4-;kB<7%f@%Lj5DoCFbP&*&X6$ zJ%j2tF24(qSzT7V09u~>;B|u=adA@8WCea?XBWoMAF8{i9fd<@F+eZDqm~744uALW zC7q$h3}mT$#o^X%Z(aBN13K*18@HyFsG zee$o*l=aDM%-Wp|%Omc{+OW9j?oc03W@Bcbv<(q@q)dd1_NP9MbW;{38Aihu#jP^) zsxJ)jnZ>sq%Ml>XF$^tAVm|~B<$|^dip(>-dyDHZ!rZe^`_KL6J;+w`CFY-PZHe&h zJd1TLfSHOmY&l$8K(_gpY2{dO8~x7jj|bY4ZpmDrLN|J*5!DU&Qj0LFl?97ljs1>E z#du-Z78cw-9*2o0+=g}8&#^-&Mb0rcEZDC=X0=g#rTsDtZLjoC!|a` zs@!O(Lc7W;k?+IiT?SC%Dy9Zr+$Tc4`5C~JoDxQtOdOIn*!e?{3_7j%`C^<^5xZ50 zbAx0;rvz(x5)aozb!`>Hf0=mI)C!{AhvncV>Nc(~h)Gu8eR!_;w$r`S2GLc zxr&o+Ovv*0OYvFV9aDT(aL*JU`>rWIH+|m}pRzRb#1r@i%_?|82mc7LT$*E(?ehGa zpS4CEI+Z4pl}G3i#ygk}<6JI02@$V@4)MyOR~JbDBYTcqj|4@1GY|e*3M4n3ltU>x zd6)k&?2@6Qtp6C=hzrp5E{f(hO33@)z{xfA&SVX|q~$b)*(W}@mO&Qp=gGvr3Kr;P zh@H~=gZ*D>a#Va=u1YiNGgU(6@$Q=!yYF6fv57E$rD8ISkWX&-yxs+dcd+~F;Q#g| zq!7oYqIf+o6~SkGXeNfsM{e?8e-tJw4);#+Wqj1i4cVT`7iOu>hEM3s03Sb+2R?jk zGEdvOzD{PW*L|hls=HS&6E;3lH+R=YupesqF5ivs7U%~3DGt4qbhF6Wj&p>gV7aQ2 zmU6fC??TR>CDE=d?CFelf<{&)wQhTY$b#kvzh5q3S64DDT?=bT_T7LP>e0IJ2V9?} z9x04U2gErvmU3^$N;O6KI=appm5Pe2WT_|WsM{Sz8A&dEP7??QJhP>c<{UC$FH9OG z&e5(5>6}i{OgenqiQ_8}6g*ib{Q-wt1Vmw!g4v4=zKLKT{quNqmJGx#^>T7lXFUse zn#+@yNRnnbt>8`B5+v-b6w^l}dGum-!&p4Y{nB2tKN~Iq;Z%1KYa{6`~ zg67CWqPqHvfjs$ljo1egU8>L!*1{AO)slcU>bp@JMRyV6A6B49lJO<(3l~lc#vmCd zqX7m*2{>1glB>KZ1@ywXtKfpLdV;-W|L>Hoi(!%Y0l5 zWkWLYzbgQ_-g3LDfim>7w{2BZ4b>~Lbtt?5oJ<+(2ATqq+7`c^h1 z#fIj+b0P_${O*a%BTqx*v-k~Z>k5`_qcc`mg_Vx7OpKDvvplBjFTs^pX}A;osiva& zex#h00=nhV-tMd2cio@fzoAXE#B!I7HczJM5c-DJ{fl^nQcuy3(IO$Q@7QqPzB}C8 zfARj^eptgi;#gYxice5=FCD0`j~fhMFXvsELQKB$?LJoDY&UTDVh1F{2M>zp-Ag3;=ZvFlfuI(<0Basqh)!}=R*9FXEbMZdku!I<>HY#CPQiqfX>29a% z*_d7*zNl$lGFLt}=-Y!1N)|lfH8f)sy2*zF>$KdG_pfVfaK@X0MmaXH=}`9_}~n5@FC) ze?fATM5i1bD5$#^L2iB9uvL)akdQlmnKc&T22TFKGdrpG-+YTHQAJ0bC@Cdibsp2Iw&?d2SbH1u%GH zXx_8BYgIJ5F1qXXft|8z;)pz{Yhxzd)Bv zWN|iWeMMZUib7Y!p&SBSkq>?;t*uCGqiB`x6v8JnN_tt*EQ&s?k{si-a2 zX7~hvG=~cJI^jZG*WW4F^N#Vm@^W0l-HBu%M@8t__$q3hWSJW}>pT^h^fQ*w{8gWG*D##f!1E<7@`y3M4aIOW`PGWmtvRvh${yRL}qq$aLrc&gwj z>nrK1SiJLKk z(3OspVd@G^dmz&sz78L3mo|kmJ0A3N5Hhcx>_SPCfBFlKEp+;AHHevkakCPN6y{`F z$4I(vs4@a6eV<;x>I5d|k0>aV=uRf>@niU|@u4o`y#B{@sC`tQT1yjoMTk_X(MWjq~eRwM0Zk)rQE_ z1`;iDGGIe#(Aiv*(25MD4ng_4gB5b2Qcb91G!0P6iVUY^^rB9X9dcMSZcFJwu?yd3 zSsp2^!1QXfu=zbA3??Sd+-tEhidT`MVBF89qe;|CM{ayya<`mHaUXkjfVmB&%|ZGT z1hT@Q9>QK27={^8H0@8OxGT#lb~ok|V+|D1C7l_v>%eT%mhfcl*|7uoVvd#Q){jmf zlJw|K&T1q)Qq#f$-jT*I^>pB(8J~mKuoS{l+X3-9Nj{h7Y5!b?ZuU(}RCo^&sEDx5 zFAq;JO)Mxrd~Lb&#RLq<2Ud0AB>p|MUF7ENf^Yi|@qg{4te;(-gUN%Dh&T~_<|9!Jg$$TEX-be3|gZ-nZ^?gXF z21FkvWU2^~?~B8|_pkTg08#v~0-})RckyD|EIRBSA9i8!?(h9MYW*S9bs&}F3>Z=Z zP0m4;s!mDM?{?oDy%JOP@1b_{cvKAMnklnNxK&Uk-tBjPJ~-lQ4?#|aj1cIq@EhjS zEl!mB=Y!){UR@c_*1H)2Q@j7}?Yo1c{qFy~IsE0-{)?CU-Iwon-vZK~gqYqw-d`N& zX^}+#Gs-T9$pCoROUyLj^~tMi^^t>B;qof&98tmBcZaXv0{uM+D!v#1A250`E~CNd zRh&Ed0`PeyFNu-pQH0gQ@HS$qg}ghMS|Rg$Qz;~#YAS`yzfc>LZ!G?>6Ft{;jrF?| zeXn~am*r0MgVm6+Xm+AM=uZYw??nHu-dkh`!_XtEAPgw?#BNl~5qx;6FBBVc&Nj|* zwZL}p=J@+()$+EITDFx8v0PAU(v~GCS2CPet@VxUtP|DrkR?mOEwroKy1`uDv1O@X z<}?Q=N?VbStQCvW>FG_GzujhC;&Z|=mXcs~GLZ6F<*?`3XH=S#%i5{R4@HGw&KdY z?FModsalk<$jX8o%2=ec6>-po;#|5B@Hr9YWMTKM z-1~cWKI#mzMGS2^ox1cg6?&mVc8a?`J@~a_itk|iB z{$xV)4akC2SMF-UaD%(SOU#TrV=Lh7xfjVK#+4>lD<-1WAV8E=o>qAxViTd*28)vN z2N4itc0eTmO!7=#zox{wNTDjL)(3)GeIm_8xSuubuw}k-$FA3>B~Xch<4*F<*0Gu1 zo#><41g7-Ztvo4`;VEr3@F#3P>CiSVsqP!s6JVFwsH`Xk76uq@hBc%VY)81h;BxIk4Mqd$4{QDsib*U%@w6f zWYii(J3u^U!bBTSoIJ5!!bGd4O9?7Q#b7vrIxK5UL|SZd-Qquc-L76HlNg9Vv{~YhV0T`7BtTW&U33R0Tm_UEs6y(C z)Lcl78D^JBPA!M5m<-S8MIW1=Q8YKN$1+siny0U3M*naCR9$P0BpPxAO77*&nS&2h2R;{zdy>YkV8$R#HgB5XW4^n;X`chgLJw!QZ5^VJ)p5;hn)`2D0?Ow#iC)GVd=E?N5Lon!DcYN}cr|vcU z3S818F-e%YF3+<zT3+49Y!K?)B25 zJD#2l)Bf*>_Xr3pbB+^`4g|9|6P2sGM7gQAI}RkfBk>Uda3XPLe~%wO zHlQJw3GrJgKU;RGkS)rpTWXh@WsAb5>Io3DCH@-{^zA+1S|spN32}MJZ~=*Mh9tO( z`Qwd^$dX^IA(^c49%t1Pvfpix_e#Y)mIlvbgCV=}mcC1g19ikd?g5@}*wWodB&r#< zF-Ax|NzX=}EA`cp^ehNvQr~Pz&l50})Q2xjX=@b=Y=&@khlHx-g{cLEsA~|OGD}Xn zE?wF)Iuf+inLi2K5;jn-f1eGZOyEnHLzzF88AVx2*&UF3L>wtzq-x;-5=KcPol(Mc zd{7^O{PGC7V|MAOoiszxHh8)ktF5up0_&JxIo3>Eoa4{U zjZR4?8I<6*%!tVSuU0NRw8k*Bux z*SBo=b3Ugbh^_f4KF6>AUa{4*YQ<`i)4JtG|r($DE&8V|)nq${76&67rRnjud`)>|S! zY6&!y3B@*y`rpYX8lAPt`#V%3ExK|`fX}x0e5Z}0tT1FFC(i2^+?MHpo6g;)(prkU zAO==NJhi2eATBS5#qok)Fl$ z@xRxo`~>!)y2{Txn*Nn-Lt$|Bx1o~yH?|FpFvI9#GB#9Ia<;TK+O1$jHHW7NC$3)a z0$4G$O$EJM6f0aHr2|}n)KyJWc<2At?rRe7f7 zggdM4R*rf?urhhN*MPv~EC4NeQK#425(j)+zluM8L+_A@;GhG;Ml{9%DCBxq5;#P< z=ji|b;Y|?pniwZj#JB2DED%-7RPa`R zHK^>k%t7r+C3HMyNQcQ%+m{7p9_ibxw&X@8qioN4VM#3@vdIJT&yo^j$ORr!CkzKkDP5Mmx)*6dH(^Vnk7Do*7=sk6w8+MeDa0T0WXLD}85lK5=tWwCrNC*E@}e1$ARO60iseF5Nt#kYYBLSH-+`)jd+V_i|t^ zaY)6T-lf?=!GyQSs|s|8xl?CC)>)tBXyeL8yfp$f-Qe;DU69{dUN!+Ka#Hka& zrk@R`7bATng#mnkMiPDel=*@4ukB=JMF%n=x?WfqcfI$omuUy?2vs=|ITSEMX!!6d z8=Y&r) zzPtuqM*4~=Upx61lbZK3f_PDHSp+zm__sFbo%V7yi)(yoB2V%>%k{4M8n!{e9Y#fM zN1~JYxZlBUPYXI3IHEt@4HYUD%4d#(i{MVha+27cqLw_$6L)M$sIh|_=vNo=raZ9lX=kH9GbnJ>LDK!kiiG= zGP=#SQ6jn|9xUfUM1DQ&+M;^F{1|s%t$XvX3-5)miyiU?{b~#c8QoE<)K6w~BHdc7 zG-)dp5uMZcs;+rgv`xl{UQeL`BP(WH6I53~9Kex2FJU;L+-1!U~^#>up~b9Lg91^mk;!arB5{`HCuAl4H$EH zPaBo4b>^c-O=fd;80*uy}`-2PgAz4;8u%OiMtzAu+r6%Xu;5LPouBDq` z&=d}^)pZg>dh!k333GspPG8<;#CvO8{7TFD@SUG)5Q!$V#8WaqiD ztOeWKIYzHgV^s$`ws4Ez&uB5Y^k*J1$pUv`>6fj<+Q&>m+=#a`kC%L6RZG=AR&o{W zT1QH6Vb4qBp@hY`JMh-kh{%R=nGUA8o1GOqW{t||A77Nhr89B@$xY)t2AGLx1|$BQ z+f9jXxVPr=gk6z4(Vw$R3|dP8AV3?}!NS;hn{cZOBL zZ$f8R2e02AzB|6QGb;gp)>#!vc4QfpoYg(9a-$#P!$S==SnFU)qDu4gs`ArrFnQQFPr*zSnz@-=BPrKeyEnZ*`4^m>h#WUs8m zAqy+G0a*3-t5D^o%^j!Hp-w<#8b3T?@yghcR+>!5zgfj>P3DWBy0%g%0A1f*m21h6 z6UtN*&X5zJJ(1=E~_+9gSQ;)HFHa|bv9A9nm;^L4=TlV7GqQ$jEJ2mBd z>x{2zwDB08@1H%Rf8lZdee(3_r$`0;n}{^_&F&z}D-dVKAphi8iR z?kM_Qo@JA&avj8KG5`Vm=Y`+#O@!P5Gsb`Nk=K>(kETsD%aA#HY259|6KuHpOtpbOAyI zgFQ{ragjoPpia=wF2=(&27ypV?GQjZ0OGF#M0P?EtYRoXzLF}LC>O;O>M%ZN(c9kI zy1cyX#MIeNmY;16xnQyN>R@mG&C&iQbeO8V9}O|zpbDpPa>Yq6`xG~27+=z5Nl;q& zk_Yqv1Ev5X+fk97PA*Z$eTbLE#WraoOZE=NY!;xnG|}4bQFL&$7X4}W=-{XgFn&2W z{`2Acq!*`fU^~C{tw!yETqTM%tjsEB0&5L%Fq1%errF_BBIk5-+)2+<%w41y<$$dir-wT1ZDT_9v!}a zx3^y-oxC(jOh=za+2u$;mS6vL@DkM2cYp2ve6atEZwcT&X))faB9hR%iNhscq7j?B zi7W!uUxNz$?qK)T!T;^Q5Y4;UycMVmz;T|&!}Onc1>VvsW}`%^=Jr^n-t7!W<~gqD zCT2HQDN$WgDwX+Ph}2DJ#8%@HxZyz{SCtw8+AfrVTezyVI}i%V84d z95p;ce#UE(s>!&{x8blx2t%~MC}vl^_-WSCtxRZjE{NS;#Ih`sZT(!uf(w5#jX>rGmAwUmRGF20I9<%sxy5T%CvCS2~pB}JycQ_P_)t{FqaR?UE6O*ged_oms~ z+8cD9A36)NHh#!|MjVgMM$y5kMhA)Gu;Moh7QNbxwzTk%oZ?CUTwt=-`v8*mY5L{k zU*UQE`o#-i0%X)0V^ZaO)HWmeIDvZ0qrjN{XlAG6_yV>v)4SY>KH2MyIfinv_3PVr zhyT65cicUA@!OURpbW2H9q!RZncpZ%%N3_y*!p$<%`vdCm+ubWzoi-~gbROwR~~me z#0~p0EhyxbH66?zLzxz>Vk@M!5{bH$_Uw&;?$!y9ESL+MA`9EEekL6VEa4=vlktde ziKLjexB$iM!vPE)w3WVaWhRHER9r#lCfUoaRT|m)Bt4_`%2BP2`kP$;p?U?PSQj+B zVp?>Gvf%ed#j3*H6=l0RETjC{NeGF z$4`Jh339tsvf*Z=P$R0FjZyt_?;RT(p!*LEPbG-}Sr~<_V#3teRb(>@$7)T^JWycx z+^oZW1U;@Sii5`8ilR6ecwYY2cqy_M@9eYY$l)$Ni`f6i=T`+P>D>ZEpo@6sA;1j# z|KsOB{NULCpFer>tg-*!#M9XS8~cA_|F3QTe=Atu5plkdRo*U9uHmv7n>i@oPeAh0 zGEAP}?13mM9Gyp|JH&fYo>lu~bVgb|PUQgVuuVG^iBmw{r$}Z3E;*()w&5GG4acAJ ztd5P+rkTzzRO3Hgnb-mmKR2sXC8>+5sB_`E=$_lnPzsNOsJ`FgsnL!Hsyq8USQU%`hgSasM$ zh+p9|!7K9tl^Y*|B=!-(ov8((2dMI@+Y(@WzR~QLL^`3l)s71ia!(wFXei zqde#+wQL)_X6f{#@_MQ%GvgzV&va9k4ULx8wza}nb-GyE6|*rb;*3~R+s^7*)#+ks zhwSF;AUH&k+cq&T9j0bxhs@T@{(v~Jtx0~demt+=57m<8U0rjQFls)9`Nw7{9V_}u!1`b&V!^Qb8iis>XBZpDMa@H`ogwd<;~a{! z*RxRG>xB}=p5Z`5z!*H&-WsI&)*~pZT#z{KBxBfB!FoNXYOe?UCQtf+h^xAdE!7%D zJcc^O^h7r7#@q=vjg43>bE|x)t|RSR&0`VtRT$Y_38m5X+WW8n>P)^&{04dBxy;Lq=voVuD_-MmU0^uVKv!Kb3t=_hdbD-25D{Z6RrCO)io%CRK-12Blo~nq zB6?%V{?-YPHr^WGpCz4*M|6xK0z+-Z4qAQ46}4<0f+7+gz5w?-Nk@snuPC@3j*5h= zbrmKISWSO_bY={=pxRxjJCNeAQ0P!&yL9&>%Pr`L8Whtks842; zaC|Vu4%sIDt!cxnBnw)VMPw3nScjoe9P6#c=0mX#@|w{N>i8Z75gmv&YKk4J53Uf9 zYCMr<4mV8l&lenybOe}@kmOJ$*8~IOX%Xh9shD_*nB0;3_4X`skGD>E;n@NCv~XGH zz~Shsm?Rg+s!kPQ?_pdol7u*mdtdzW;(UD>r@07rd*0V@pkp$Q*&; z)wuya!~XO9`FBs<``^!=KW*$kH}N#~pT_?4t=fN#Z}VD?;$iP=HKQLOrSH9f& z|93w;d-B*l|NriBbN+uLPow`e`ro&z{{eMfWTVBM2F!};CW0ttXL8-`gRIE<1O94(%QS}KC>f_TJ5SgZmCWSI2jQOS9lrnZLF}?yp!37b;U(&(|RiVNN#L*gi4#Oe`KKD7DT&?MTT+m)2 zk9pw?92IMtHwv*}{TrZ4*-Xuf^cJ>`|gTnLl0f&hsX9FYVk2xf>2Q-k-OxRPU9BC)kF0Z_*v=^4Bt-n&2Pk;jY9-$P_PE z6no2%QC5_2-W3<>`3!yc)PwrWgc^_wuE9sjxTH6yk5pI^@XvgV?Y-WqPcWFRagmP* zT|>3}ws;wCOD?q-PJZxlBH+2FOG^E(xXA(H2Hq1GnOj&y22MG{ZPO*UjY_cKk8k}w zPbyFZK$-@Eu|h2k_GOaE(21tz{3@QjvSj1mM|;2&936ZQg?4)Pi`tIY42Wyy$YkPS zyz&d`asNCW4nS&HAj{Bf#aB0LvvHPm%GBRuOPVNEe%18YoqAEQ=Ai+sTpwoGj@oeM z52A*0%o4w=AG_)$3s|v;(kY2j%%m-XR%+Ci7Hx~yq)}HW)Q%E8kG3{L?F}irdiLsR z1Ybqn^?ZQm&~^!Dj(AY2?b5_|^)42s+v)|lUI;jLk8L~?8b$nMvUEle(DYh(95|ILLC$~8z z9S<3-IVI87RC3OeF5PYnoaG@yxQM@`7t;$Pp#eIS(t=@qtOL@RuSdrs>F`N1xx_^B zPlydXL2WD@2^ZdB%|q4akDdNbvQJ4+rzH~xT6o2cP%0-7G{P8uprasEPkpqx0y#mX zIbe=d%d`+f^}<~c$D~G#GSbeH3)dLpEq04}@;S|>1M7e?et zl0$?!50gU$>k;(wwRn%gB9=I}c9m@1HXloy%u3o1H0|Rm?N%@Hw>1_xFKVmWK3PXN zza7ey6v>7+Z&^t!Tz$N)7Q!E)$FNlk6EHBRD333xpRFPpo|@-;#04UJYi-17=nO#b zqf6fWsJ%x!_+5c9LB%`poEPWcWDOW|Qn^|4=JcAg#3hs!>mXsD&qeJJ3eG}?2wnR+ z(Sbp9dI15=P>hXnZTAeGjQ3%!*w)cCtdsl0v zV2#7ERD^?E86$KCVU16ZC}?tVPWW6y2)9C4fZT!Ob9>DmE9IpjsmkZ24mI2|(}#DL zV=>c*2D53V}i*WpaI zf6q<|yEI?HC+~BhGC*m1!S@f7evDj0#xv(eBV`s*s+>&AaFyVh+7v@{cdCpu)Eyk? z1<0}KSZAvcqnc7O-PmbZS#-*CPn@J@G)T7J{6jReDdB7~{Edn;NLV?;E=OzUmDf5Q zW^qV4*GhRYrF(#<(;+fh;hJmvAroeYG-e~kux{}bNC*~jt>#Xd+%VKR=m>1FBi=q= zlYM0Q!(m)|n4-c8nohnX{VBFfm#Dfx9wy4W7wHgmnvyOd0OB*qO-JlKjqA;sgti-X zfq^FdY&38qXnT{s9Z}QO;_*+f4tI}d_o54zU$EYYOrso*l` zQeMjiYjRrRZAMaT+V`)-)z@1UJ2g!%%Oe{63}2b6qV!|k-(4gQU{|;1g#*-|7LKoO z1^^Uc0(Oq`sdq)s*mp~3oA32fcmX;S;GL7|2=j~;Cl(VAB{HZEpP{`kXfDX5s?c?D zzhaX)=IKny5o{FY__`k#@{*K3>_GV!S8)UrCl7#8V8eY4+2I*qF4AV5L40+a2uvIg z5ZCk$i!7O~qb`*OwgSAwrbhcvg<}f*k!-+EH3BeR^ zRkUZv4C`pNQF*^cNkLOr07DTxNoqezUS=6HDu^7%47Cbx|W2=}cU>RJ0w1sL0fov^5us z)UpQ7?*`&2VB&sNaNo2jW!d~B_>}CQjnVb4J&V|XyWMn@ zPGBl)nt*56f1f}5;fZVieg5QmWB|8}I!OWI(0pOND3UN#zW&{FjF zYFpplWuWDc68(V!F&+J5SXOyMG$~@3S`EGhO2plY&7netIv7ooGmPFbFhd@>VUQ$P zWQ1KIvstiF%{!v^3_v7Rd&`I1DJpCx48cqtgrHForfLs!YJHg)1BTI(gmEweHU-PT z!H4|Jy){1K<$?Z0jFf$pDV+VwJe!Wid9n8~@Lr!jJ8zFg4h#|>s*6}(5nU&s#~xF+ zRfqAl$Z*_t&>Er=_KGbTk?}F`-W`#8TRtMMi1pP-t)V+){674Q7m1Qfer2R`<`*xM zNy#|m7x!gZM-GUjunJJ!Yan%`x4@_JO45IZKcU-8sEYMIRDs75uB5)X6%98$_oY=d z%RVK!OYiu0I`*;kIvXTIUFuPKcKG zC`p*4WP;#ObwOO&uH|y->Cj@~{Kn=eBoYReq!gWjAtXoVaXtXi*Au)Q!OZ!I2R`mc z!lT=Rv%+qh_^pn;XprL>eNw+9_w`&f2UHsQsamO#r5yD|zIGKD`QBDxS7L%+!j)`Aru3^{+0PHN z?y58Dy`#{W?`@Svt#2t(8ZS!Jnm`Fhv5_T$s!i}?RYiAj^%R`y(rzK2i-y#kl5ckR z3{^+H3Mo69W7_&l;Jw{|ukr-HIF-U`PvCR#i_bMGm7mf=&Ua4%vOhQ~Q0SvkN2x(3 zC-pQP_hWzwnc9x~&gbBE-sC`<$8}q4ao$>cvZa{Vn@dTCr^-xQ)d{L9b8uB8l`2o0 zRhi7HI+0anIp~ib z!I)f~!~f)>&eShdY5SM2OW2>ZHsK1dj?UnI_STyBLTV0n0i`==K||;X#v(QTq|e50 z$*cmetfH<~pm7#FHV?R7+b#n4=InaD^Is7YtJs>W4Ls%j;ra8D^I!hkKL36C`1yCg zi=JQ8n62jNpcC=eujryR3WS4jvp(v$>aWs>2P|DBFqh1e#8+3IH z!(LB@?I_eO56qZH?V#)E@Cpbd9wQDT^q>Pdo{DW#k?r1W*Xgiw)q@3qF(cb5xam00 zKBoi9o`RmjUF?0g3mv>jCg&MbD-9@7!%0Q-lU~mn5qTkt;T)I&AL#lV;-}!Cu%Tw? zI>JT#32F=mDbJy3#2$%(I*JE_N0RAiniw6Wda|?Jpx;q((SgeLvz()?AZt^BSLD=S z1T%y(#akH5&j7)U)%6ArfA%>}iK6B83!)~9C?oF{8ly&(#seUB6`u>MP@ErpV ziXFpoWhgTs2eX=-PYadWPcv3h zRpEXFa9t;YToCyssS5?0Qs9}SJDDzJtFj|~v z(;?m=_L?nlp>aBNC2+{G!@SAH!f7*cHFdgTu6M+wJ6|QRotlfHB`R!qa0E_v6ngxA zFk*I8w;vcB;0)dYqmWEM2VU8THvbd%YA+6tsL`@Jz%@6@V*Ahz!GV1cuH3&r)a59; z7gxmK?Z(wdnAc(AeC)Wmv0|>_>nDt*D|MnlhKKZx& zxBp!4@I8Bhk}mDH-7frv)YI*@oe`Hs3McXLzDjBF4T))9JB^%nPvkVEPSxhG_gG{r z8kwz;*&3N`KAA1X4K^gXS%#Z?E560ZK(9%N)AJa+Lfj1G1|&H>PxMz;q$1Apma{Oq zU>(5^A1tT$uaPSO`W5tOZDG}*L9c^fO^(zq4GV~nM)1)ak|BK$j1^n@>>*vJsZS4O zF%dG*)0>eY19NcCWym0F_t7wy;8=3oL07I69Lp|5$fvRO)h6MamK*)4Yvjh#MRAwq z#<^{M0giIlgvDEA>(jBimoxSm`|K@{(iXM$-3?J~K6Bp^vf8}%zD8KPGs4;ogI|Ej z-ebA#z8U-)!L1S8ZneSh9>{RF)8H2p=Wf#CXC~UYdnUiH>rs2Rp4It(_lGI)<+=U8 zzkB@j`O_a7|L?E#H2&X>|M#`|fA=#GoBLc!IAR~>n8su9BJEFPE|;v3e*wM%e&blS z9l0rC%2LFb-r}AkIRzkrd8Kq8{kTwlfVskv7PI}zWv|ZSaoX>G7Bn6gGChoZWkZ6( z-99B8;o8hByBtQh!0Ps!?l3*61i))VRfaEJ{i?F2==hV$La+_zR|pyZK-Vv;@N}Yr z)bue1H|jk@>d0B#HQ$(zlW@lc*qP+;WdZ+049k=CrR_~Xx?_1#6O71 z>(JY_n)wb3x}EN8`u7E=RBcCZvQhH!f#AL>RzHnt8`~b|D4}jgZw`U={Jj6Je#_Dn zMlDpQZ3^n8Qts&Za)-L%LD$cgy%sWGbsdAqs+h(X9nC1J&^tXT>5;Cwn7 z85|SUJ7&&QJ5*V(j-rFXE@V|V5#+Hf){b86|Frx5)p2+4)xrLo0^+0>Qe|p@t-l$8O<0VyPI+q=g9BP)1~Y#Z~0)=T;T$*fbd{^DWif z9AdI=VLo6uC)0FDCQY>b@dEe^KM6v?nFqu|D56%$4ade9jP6u1_R&9=3ni3oqQ0%LMEgOk_tKl50=64ok#)=avF#r zc{a}Z%vfz-)SF5Jr05u>uriXO0&$U?sW&dpK0QJ)(Nn_(Jr2muKQeMs8yl%iIxQ$7 zWn;9_H!&DLpNcaakxeUXQhSKqjI{)5bfA!iIqavU zq8c9`7`=Ftl{EdMZaR?}#8D-Qu~^$c9rVh8C(t)YNra8_tBsCpr$Ad%3ynLil5Tb= z-Fea4*w~oCr&<@1EA5msGR?!d3HFVoG~Pr$%`;F}LWQal@ zB8Z`jvSv3K4aQjtGl9~u{9&Iq>}4a6@9|h@oJO(;VHku!^}<+SqC&Lxs8ax*PO>i| zCm;YQFj)B-p$|U0uP2#q_)!NtI12)malfHi40SNrt&CiEK2I{o9JMT-xv@>_z#Vd* zht{cPCTQK0MS+G0PbQ==OG!`3E?{;l$Q;Z98tK+-!crvrJECKp%4D7j&RXlg-u?%2 z;s5;b|2iLkzkxro{(t_B@VW6{_(C8a-ig2XHRF1aUBu}KzG>9|4IA6|FFl?OqjPBM zcRJX)h$sDXo9|C3wv?I~HOtZvIBft)=7~nG|3Q25M=@|K_~+55OZ>~>$P`pfxNoqS%<@z!Z7L#VD`yO2naMO;SX741 zR*G&|AZlU1#Hq2`aE0m);^1eL2R|iO0-9MJ`@bFS8e3$3HobtJkc2fBk`{^npuJ7< zX@8PAhscbC1%OoZ>9EYfV^m-eb3!pPra=8|ntpa%qejOtyL8HDAOEA77!UTtngN-# zh0y$Id9meE%)E4nW@x5E{7ap>-Y6+z%ax=kyB4+ZK$vH09HW(-C%=j^|6XJxk4Si5H z)NjKhVclkE!Ucx;ym(?;6~an_VQ<8xh3R0?`oi2`nDxoZ#=oRS!@qPz{_UT1o2G>5 zbc$J1|1ph+ph3eZb#<%+JfjmB$C~I(vGuF?>$ff0CwM3S{B29CcU!;8ZvH0DaM61M z>Z|sCTa)MQ0_KkRw;f4Io)SADyY~g>dG)6mrs>q~rjpq9{>x zmrDYfA8==^US5$_j#vK^mnP5lOw_zFAUT6JAF2aCy45Zhc0}vDv#ZX zMD|;Bb+{nEr|9_Ak)hllYt`Q@PlogfdJv9)F2$KDY<$D)k`DOLM?v?k^@K3jdwF>H z^3{G9I@EoCv@d;5_V(W$AN+K%w|l(bgN}Yq^K68(9DR=Sl)N&bH9YNDo8;4Et*!2y z;S=uL8|x&x^^}{pvDy(ojalhM+9hPr77nb2RS%&4h>*+<$dl(lN0KjTF)1`0S(LzJ z=+1eWicdyu1=$^rH7C}jE;btuI?R)o9u}xZgpb}OW_K+fUdC6&nrg~JuXPkFC!rkP zDEXY^Yd-3sa|*PErso3S&M}czr`j5fY9i2l=sfu~I%y6#5nR-dN6`sR-xN>aC*y(4*tb7+c!%30BYkpo9)tM)J1t+}dX z*TJp_>AB`8EUfAQ^r+!p8~6(JgonUg=&czp1P`O1(z7YBQuMi;gasGZ<;~|xLbR%y z$(~YSYVQ&@C)gj$Axk%@GH5O3QL%X&uqS(yN3AGm20wSZIqr2hQzHRaDrEFhd#-&VLMWn#qFJVCVR7Y zqbfeaQ5!^wy;q0tUvwSkm+-)5Z0DLq(`G%h!-BNE1&F(Rb{c(fwuO)OiTm8bLls7R z0gG3i>Pi{I{}?`kUD;;b0gWZeTPxm_eW;@pFLWhc_MF3Y5QG~fmS&Ux8k@Xoo_SyC zj@VaSbTmK^XfwDxPl%p)`*sHVl*VbuD5ss3#@b*SnBkg zq;Gc2bcVBF$^vw!MqE|l%QGqIoXkHwMDzU_>L%UfP!4_QdrJmrq5HE*$M9{#YZKyb zyR)zYlUH-0R#84a&IFjqke?#)X(lL-{R?1!&MwWR?ijXMtREy}c!fwUG8trx@iUI| z_yP@(MaRSS+pH*3+y?m03}H~4`{b?zJVI+!J@5!&J{|%~)FQ9CN{3nL#jvS+} z22Yu7arT&&d-*8DzWUkdl#B_3=yMvILWk7zs~97R@r$-oE%FBy#M+$7ZN7#mSVQ3q z%~eW%>dD1;q8#|b3Y#-K3vd!`$8mv`a#O$6Fa(FS24;DVCPK2mF@|9>YB@zZh`DiV zV*@$#<5`N^dpQL!1Z@FR%t)beXCk1*IODG333vz&d#A!x;c^6aDe#!K@fiN;+fGmq z(=nbH1S$qWJJ2y`S%A18{e^5nytx@p`E*V{4-2Uhc;@67Wwa^X1DZ{5JmY6Wh z*0u!g^!DF&f zko4O|rv%g*>=$@z{5<}gjMgXS&_ex5zFfjb8OWp9Mzq)H>x0)=2g-;pv z4Gy($FNKxNN`RrcvPK<{{=Ja~m%-BV`uxM53+Bv`2gMveGPWB!+7efkSYN(t`(a@4 zndpmW3I>O>qLZhJI5|OZr7n96bCw4~n{Gc>!{%GkDz2CDR=_&I>&iQ!&`mZxq8wXB z4#w72p*W(8P@p7y0z#U(9qHLIj;YF~iKQ$591QAYxpdby!GpdOPbP7nF2Sn6{|KZA zc;^@uQ~K-lN_e+Wlt+SYU#9($BU6k5eaaKttfgh@7P)uPlAglaJ244#an3H>DE!@EvqXr2CfRwVunVzg0Rph|*K(}PA&v%S!I+NDXj*va@e$_^NsI_bJ+I!3V*q|FaW_U`o* zLVLYXd?(!8wREM=XxMcw6=rDddnL?i$s`!1-fj-V+n2y^3xZQl7J*?Z|4}ins#80Y zc0EwiJ|gYLD0HI7sEmlE9aGsP>`%BdoVNInYRAhBb!aKedjQ?~d2%)##<>Q;(RSDx z+rob~i_3J zcWV1-h*NtJX2*jE>#+?VW_2Ynh2KfmLMV{J z0O%8b=9{pQs+*}s_6ZLb>H%8v05aY6;DUNd0rZEcTcb*j3235G zBD*#bEQ0j)b#e>;oD8$Ej5%pO82K&AE~UvQ0%pN_s#Mt-UcjauDlMee(F)aN5yGK_T8)sPPSG~#o=>QbuMzF7+lB+IzY0M(bHBo#` z5~Q(WZAgygaMl@5z}Xn%Ex9KflvRwFC9rg0t;1;nqqIHLk4PBK&D2tM(4CG^_%Mel z0J6rt;!=5Z+2z~O$#lYzK~oNy$=Z_7svqhAR%X_^6CdznB?*cN(4L(o|1{zxiY)D^{mMWr%SL#?*}Q!V<1+!?h++CQ>W;IOc&6zysn22 z4{D9a>?^ldb{3&~?|t70?47zXvFTMrGoSdxr2#pN&w<`K&x(n=g*jDPfwwiy>7L_V zK&c4KoaN(RUB%pmN=mxM`?6x5gP*~|L=e|m3s&Z(FoaF%?&GHluquXl^?6(n-w%O< zr6iGymCT@QAsehzc>tlmRacpe4?*t>7BMp;9PgCnGx>w+RvN3wN zWBl#Ut;^bWYB4|`4z80Oe<1{jiMT+x8U7aNq({qL*o%l7cj{C7Kc?9vR)HtdLAVcY zsnXt{QnzFL?H6RT6D^#-UrxFlB6|l<5(8xcY4LQBqBb4wm|4QH=Fx|R$vmOF~YOu}@B9S`~27pXmY@DMI3Dsf;E;b$EG0PA|Wwe%boDv7( zG)AQKiY~GNTjNMmo@CKwmVa`^$xW<=cg|%kN?_cdY^9@3V76zxvU1pK+K}$u0}wtV3oK5j|EMM>$~Cg>yg-pzIRk(7L0EoG1Zg2gE1=JXhlF zCcNH6W7-ztvY2c+eCK>}F|+`CiF4$(Zs*UjNdcKt5yN~XU6)4%_Tz^UQ@b)4moQ;i zQclvIl7tHzzR}fERaH(|;nUwLHoOWtRjkuykW+@GX6A`IYy2+@4Qu{x5bW-2%;L?L z6sUzj2UV_9aSG<5TGZT8No)hn{25l^P&VY`a#h2~QCKx{y2}s#iLgq9Y#shpq$IA| zcS`KJPB!F7R05`46qpR-)Dg$=`Czy6v9xEM0984ibZ%wxlXs)j+rg%{hnN5<9&Y#k){A~0y*)U9m%oohXwqmjy*Np7eg$k7 z|2;Z-L;wC?IwqOz_t8)32v&&5$oPAhq|eD{n)Ln_{jC>lb61Qo%hR)TM~0Wt#RsMg8*x(KxJpje*E6K~#)CM+=DsdG z9Ta0#BS7eM08a<6BjH%GUTscYM_72h8Tc|9wTaCeNYShj+3~t%vVWb9U>;FOzL4H& z=yYP zG`qF7Lj|tk$M|ir6?vf{ba?8Xn3mp?u+J6~ackXU>4v@t!)k?=XTZv~L;nq$(00VX zVbj=-{G(*(FDL@0k-ky(&r8Lq^ipN_93;bJMRv~@1ZoMpC+85FZS}m%HcOjVY%G^cTP|HLbLTCWL0%WOTq0N7S;POX*lHQ+Oof&#-Z+>q~cx&00M+}PgkmhDYe_%`ew zNTH3bV@X>_kQd(_TSu__^=%#D9r$+GI%w0VWt^arJ5=GW86_OK<9-??aAFLT1SKxL zjRuLYYK5Sy_T=!s5<9|s0=0x4q4A2U;T6SLE;Boz+wmYRK-az^=A_#hBt<_@$DGLs z`AgiNP|oCml5j~=Xv_wU*$6XHE-) zQ~5^xaCkC1(O_oJW2 z@8{a=UyZ-difmv(Y2ohJz=GYcZvzX9lefbL_RTrzIKuY*w1>&jbsWQ(_5M~`$nKBJ z&M++|lFU*ONOVC{+baNdtRP+MRmD4PQbS}F4z}LnOWUS~1qyQ6(bFR~E^!%!e}FKQ z_Az3bs;yFWlUN~R3u9RfBL{LY@0y>}HI}udEo&|hx$~B_ASe3@R|%0-bb)7M zUt+3n0}xN|Ds#P!3BHf-|-BJK*= z>7Bi2*cjHX->@b&oT9@b8!(Tvt`yqpNF%yo!5ylWRJ8I{rEJ@558avXGcBJ6ub$9GY!S2_$BZY;h z+hIpq=HA#HvmiNQ;{CKBHP^frwHc9g$h1R394uX+;Y&%_rXmot$wG#Vm+>hrI*xkX zE}q|XyFEM;`kag?LY8PDh=p>=qvehWKVu2*TcG8&mv zyEbdy$X&LxB$NiIxo_5(rW&8G#^%?nHHnyB`h0Kskn>7&xK>9l-Q%kJm8vh_fbB|+wJh$ukrJ4; zwZ@*+*t68LqNwl&Bf0ZNtuQ;gO@ZMJY~KY7SLOb&`q=QA`7aV2Ue~@x_bhGilHuVE zCVfu>#A~9hb2U{>LkWEt_*y7Ryzb5Iz)oX3yeZpZKwgs1iv*?z-6KaysnpaatSIB& z(b1c*3Gl69T@*>6VcVpf>;zAmBCk4VEet^rZPc=ay-YIY#E&MsSMlT(q7wh!!&H#M zz_$mYR=FMT7cx5_=GP2>YbGv)Ef1|xdE(C^JpJ=@H~_ZujXJ}%4Mx`(+*T4$-IW~f zj?pdL|9L~Id!p#=FutuYrn(^;)B~r>?--Tunq|)u=kKR^uW`Ejim}yKW8&j@hs&7w zz6HOss_^QT!g7}2W}^jNbt-BIdz%pj?u89a#?t|+je&_8r=(KsH!Hmrf!EDo?5ZK7 z7s%Lb$b|{!U0G!INqjN{K>#GNi&*Hl4psO8FUdzU~ zvY75SU>tNBS}3Y}nQ?G&S2)2s0~W%wdV$?5_Xn?D6WRS6vzEyU--ZdM@p4*OWcRyk zbP4x=-q`N9)add}cszL`$o;g7+!eQ{+Y;V=HKq&>TepmkyS$m`M{Xy+*KfjjhUH>1G&+=6+mbVY-G;=Ozod z^9H6MBf3?w&P{Z$${2O)f}NM`1*;BruG?84EVEJhMsCv?(aue_-h?}EY)Z?AJ1>> z5bxX(J?>Au^VPU?y-YNQnyYC`xonA;=Z&9LV+AvwRYX0%Pfk_=hI1E3lv49kW)T^K(TAzoni|-^7JE zTlTx3rmVYiTkdw5v6eN^r16EItT_xcx>9$1@)ViFL43jdVFB~Z-8Z`s7I^#tYYWcG z!R~7*sGx*qg$ttJjZ;!%j!{otb4*zsSf8No%1ZWXCFufmjqM1uHRw~NO~>F4ch9CX zn@fdlI=Rs4ch=-zH)7i{aD8iRJ4{HO+WdZTvrg3OnP7W8@8pDg*%%^LXowKgTd|2L zf*C~z185tyb=*UC`+b;2FAJoV}XV0@CGyIp-uV{~W zo?Lw;IoNik6(f)b?j$7zqv${>@i+Y&>;WmIIc#6Jhb5Rk4G0BZ;Ogn8<9G-^QHP8` z%fjA4ZvzpV;CZVmNTUiVmocYi11Msn(QiUf1P;zXh8`Duo028eB5D;=z$(o1%jjsD zPLd5AA9g1MhtPsj^njh_04?JrzetM$H=Q4&BnDVmS#~yX3ltubT=GPkho}NcEI77J zj&M4N`qKgg4uP5w7|fVgWT1eNoeMh?o@-2}CuS^2EznhpZzcA4n)wksF-fYUfx||F z!cW+A1>+$sut_Dx*o=}yd8TD|#QoRP5Exu~2B-x02#SV)=9zq&;M}ObamNR~9XFyC z0Bj&8;p8MP0GpV5Z~`3RWIAD78OyvKbdikownemil1v~L9&bK=a{T!5HvO;j`0?ZaTi>vt|K|Or zFt7$2{~0#;r^{b{`Fs5Muc!aLyQ3YVU-Wr#|OmSq!2E)xXgQn31N zkS>V8H3(PL)D*iNIrLhKMi~f2OERgCUJJqlx+|x+pGcfA`j0yvZaFf7@hQj{)7;p4 zLQqz-8$sz}Yh$ISL!fem?DMEEZMgOXQ&~!j(fUL-usI%1i%6J>Nrq}WRY4|7L8AgW z3}rc%DW-jt%|55Gvc$t&$D_hCqRgcv7#rGrr_;hACgZYRvi9YR)fKWX?Zo%=sne{G-O4- zm%26P{NhfT^UL}DQs(@l#+=`n^BZ%1W6p2P`HeZhG3Pht{KlN$nDb?U#+=`n^BZ&i zjhpjBO7mAS=Z89S=gj#gDeHn8;niiS7w3@fLQU4gq;EL0*zA@8&4Setn z*d~8rZ;7seRD(=T;m81i8wcKMW}4Zc85t;A5a_=fk@3 zi)%euZ%6*yr|TcD?|>mVi?{rkVb%_`)M0}Uyg72X!6SzSHdhVZ52_jY0KCck#x=Qe zj`vmcx$^GZIjt_lTN~Z3(e2!!FQeOayTFApSRg5Mq@S#X<)*c57aG>EAbm+E0#KV7 z5DVMzBai#ZN!~`t>rS#M^JRzW*&!cUi}sA zrKD`o>2LA{xd#nF#@JBM@i6br;V~?kI8W@;Gun(YjC&!3oZ{c2eHfY)=jl5sO{|~n zy*fPFx1n3`kVT;S(2ucqynEvjnB7EhJ0Wt_3;|^IB9TO@(tc!P3c`$nmsPQC%$KW~ z>pH|VG4kV~dL#^EP3pRpyI-GQ+Ea4kZ zg*^xdup=01ckk7~{+r|O!JD5BOT>!1C|vroWl1=nJ0nM0vZE(224uvQ2IWySx3FmO zGSMsYo(mRgoF$=m*g6ZKh#8-fGuh~DGoOw|ltM#RUs8GqV0@*rg9*Qp9Bx{22oRZk zc1Iu@=&9*>d-^vj6$BQ(=ou#@795->78Okf=q6T^@t7NKe&;v`%hJj)(PC%!)N)S+Ea zlYt1Oi>KGn23A6DFFd@ND{?p6$l94`^gW24*!_WwI~Y#6^Zw1j>$k7=UjvWXf6-e~ z#t9S9O2r(fiAK`7W=RJZ&9^S8gvt6I2rKT+(a0V#{gcF+4v!e@_3x#Jj*6kKQg4w_)4~c6a4+NXC?Fh z!_)7dxby$y*>_KV7d^fS1bpN3|1jEow22pU(77&}PEI%ffNvha-j|K9^7QO{f){+h zlMyyvz1n;55Wcir|A#_Vf2$RN*mCxi}5hUtzQd<0!Rly{8fO+PH2}FskKCi3sEkLC)8nl z@M6vO*4E|aB}m%XS-dp8HROWD)~kcP{WnMZo6upZ@_sbLo6h125bXO`lnW~D)0OFA zd`YoO&hi9>zzq9)nUl*PNWj_Y zG!lX^{s&N9bwME$$S%raQ=qT1$GP5Qfya6RR3AgzjPOnoD(BEr*L*VzisAH$gONaw zis4=bln2K6{g2+QuVCUw*_4}j?ZLtqz{)Gutc1#-v|WgrwyINAS?PA7W^yr}R5aPa zKsmCkE7Tp!NdYqTWlRtY$->}OdkNE_sQxJEnh1 z&;Bw^KsoGZ!|4Sx1x}MkRYBWHc`3_a5h5;^iu;4%jO6W94zVP2eyTW26vTrpSEp8I z=}?StjuD$kd1A`}a{r49WT0PCIS5W~OB2K~r`Rc{z+8Od1_mxvd^gV1ix`JQLOgPC z6&%9;MA4UqSv(Nxk?+M$>^4zxA{ZxtA-p&nrP5LOV1jm!LBS>kz+?mzdkWkuLcS}! z&I$1doXDf4Vp5$<(;=(~hCRu~h^0RtAHUsty741b?e&l$q*<>Q3AIL9B*?-r97=1D zw3Kv<$@HYyCT7fL9LbE5h$|)4?1#Lp6VUmhuk(Dh)w2al^~_s^|jm>;C<6(q(RDbmSz< zXv%*A6b0ryo(@tZr#f8^nEGL59*{KF6}wX8M+hHbKMVo^#>iq`%N zX1z~_|CX?*ZC9@2jZWDTG+H+$oU#?owr8)0SSQP6CS4Oe2G*NQFz6usCG1DAs~n?^ z%>!drOzE#v%I7Mjd4ev|8jIcYM^0`#3iK&AZi2K;_YArigt>A-+Mo^=ePKQfMHw*H5PDvpIe9|xyuh;&AWl1UD~3L#@4_vjhuAQ;u87;XM5XWHv2P#T3Wu=;-K` zw>tdOwVuEEp!aKTEo#BVT#%g^yO@E!*_&5@vzoZxrTId^9&sYDX$=+Hz7+qP}n+KtoC`<;`VUsYLIm6e%Pt)#{r(#FJ(|o$oN2bjBUKpHfBQkXp;E#{~xS zU}Ns&z;fiUPiOdW{kf_`qJW3!=@Rw+zW7e-l@V@ybILsSofgqk>MS^TER)4#2?72^ zT4&vd1!RW6Up4#&A3rroixIXc(on$Ql8AOn%ke+C5>bMJsu__<*n?7jpY#-J5mGrN za$)kv`+B7xJt$&s+D7Jc%*cLQWb<1le|FR&N%63P0=GFAO_V!jo#&40G@$wC5!)3b z!LBCs*5FDaL=QN~A0t?|_dQG;y@P`8rU0GV7me4I_AnA}kt0^X`Vz20S4HOx$>}Tb z&>~eAw@4h}h=Y!%>4Dz!j-YNA#@)gUoJw&x%59ppQLSIG3mmTRx9A*tL!2{W6{D8n z%Kav8J&n#kS5?i{-`ui+2sq#CunpVT?q8$5tYa4M04{gw_zagg6xVMEDJbLPL&RK&eWM*^&C!e3qN9 zNayB_R2VQfcsGW69&;gwHKOGS&0k$QCy|*asAOr0)M9hk*PC3S^mr7oGRO)kUWzZQ zFmSvEVjhUPq!9Ne3xTd_>^!g0F!`j8Z+LjtPmum>Vt)%`8ks&FUvU%{638ANx+uboKpIM9{U1 z26f7=PshQ>x5)mZ0#4E{Yu&*CU6N%b~F_ptFZ8z;Dh$&*A_{1Rp4p-hsmtfi`};Gm~30ZS?S`W@h;Y@hx#&e$x-z}2;I=Me+#kq6Y6pLn>FHw-yk2F}Ss{0#Ve8n+D-o=Q#+ zDBvnzFjJl=9C6H9B5<;i$Fq6zxSClgu5bofo|S;$=t(ZDG3r9bTv@3EhwU=!9J#VV z2vgz&fb|B2)1rNS{T~@X+VSErC<~!GfEbH_X}_{PK&SPaE8!4s54^q>02k(;1$;T^ zJwLtE3V4t#R#9V>5t@G{{#VQcY5vUEYZb#yND*@+3A$l2BupetDQkPokO)-K8e=n+ zF`yiqfS-`4Wv{L=Zc|jzY9a{RXMRJ^V4Rksn{o0_eSzdgM*Y&pGtrlLXiL)j0uNlF2r~xAw^u#<-_EZVw|CdyingYLfrQJT0b`FJ z{P=jB`R~Uk$51zZ!E``yBx_%G=vss%t96$ zPAZ!E!$Z>Yl-s(l6^4ZSL6^O&``aHHOR4C@wo9JLCij2ybwDhJkYX;gGfaVw=SYDt zM40!k~!79h11qVbV&ntRqVr)55p@W&(UXH+!;6L38D!w8E&GKJg3^dkluy zs5w~rnmpBNK_t!g3Z*5&UlsLDXi{*Dau;^-$Kk7Gx_dgoJNrxkc=y;bGS#T2fPQ#V zE-(YwtI^B-9&FztP6%?ZC zQ_R$MJn8ET>hDrLmR^HAz}u{&peTreICUZ!O722vBcMH|%= zlnG*ORl;POX2}czX=EijCIw%Flx_KN|9exn{T|M)9PV|ILD$4;n}HCS2gE0Zqt#a> zvJ`e$awSWGLLTG0EKL#-H6Mx|R^4Ajh;Bw#}hkVylY0i zXEhI*8eiSoSe;$9dC-ij1+{ee({n=eIU`@k_IC5mGc`46h{>E83qBcPdJEa-8fCgQ ztz{F#tunI0V0%D7J0jdwjjE5aXmq4$G6MQL_rvQVMb)Lx1g~8Yg#FHfv?}XB7PfVI zBx84dc`CyON;{SwXyO4)LI05QNYNBLEIwEPCA_~T_eNL4! zJpW+{c==EyEp>_Z6aFZW)JDPQfip43nK(Oz6XJt)enz$yDVgB>fKqw!%#0G`fObU2_ltE#jEx+?D0jqa zHD}TvKvb9fIS$}ssLLC=1YOt8R0;1+Zbe~-x=vm;s+#LtccZ&~4O=c&dnq&jHQ2DqMCh+y=!GRiZLTs^B~5#+ z(hovzdh^y)RNr>^M11Kk6LNRi`{9pz8r?6w%ihL3xo55=i9bfA@7gEHa=J7nfqt_| z`2l9B{St`%pwo91qmOC((^64s`?BJpT5cYrkA{q}O*0P1hpBc|XY59z>=0gv%pICv zW>;q!Vkvcn-X`rt+#T|L((CiIS8A9Gsquw+WXP$^wR+(~#$LRTQfZ6m$lhjuMfqZ; zoQ=tzLqPFLA7av$Q&C-kP&}}YaL|)gr$k1Bvd3kv=IS}#g5CnTwTGq37|=7Lf&`os z7^e;hG>#2kn`z_}MP%SadeM0rGa1F+KPT}Ee6YS7guV+R900$KRC*A<3oJ_U{L;Jo zxWpTt9MPE88TOp$jH`x0r}^lxCOxF4au@*xG_-q&~MprAgwRmQRm2=#tE`k7lGZh#9uP71%#dRO zlbPblzYw(ow2iGL`bZ*NSq z^^l`y`0dM|y-&Ic2fZJnB50vn!?k zxo~5bYJ|U>8mt50?)2MO^bB>E_um}CXizG~G{ESW8Khz>N9 zrg6f(nw2-RJQnFN|?UtQffw^9!K_{~IX(0OSvhcp^MoD2|3ZUBkdE<4X!+OD+>SGZp#S=4>E^AU%mYc*VCdK8Ytr z-!T6X?53yi9lR8*%;os#yVn#61Kq?=1l;5ay2SMtdd=}MW%-@;C}O)&@JDCd)EY3< zx>TCE-Cw`g6v~sSG4CUW@=zjS!$GZrn*s@MV*Rg1_Y^R(%HQFeBL`0F@lZ~(;lC6n zRCd_>u|zgfM%XHfM$H9zLr!(B=$p(8xWV&WGo|BVapqu{EvZmbc9akjP`%k_A!`Wt zcfhV==CeIfT7G=~eUN@A8y64R zSMSG}J})PVq(T=}>**}XsyEmW9@ymPSU6FoLd$4pT6l1*_nt6cg@61y zVbRb%|F(O=G{SAP^IpxL5$@aJP%R@$YXW_1MtXJ___0;3xk=bT;0ITydm_J}${pJc$Z#t2dHJi@IvfXHHS1)pue;H@2WOfiU=7}%3mOuLUXGvwVvN&M0l zIPqTSwHEH|vxLQM`%R^1!i@YO*EAJRLr7L7e9-&??{G0fg)ST0bgk*J;NJpIfh-`k z*jSk>sb|jd5riq~C;OxX$&Z=#Sf-7W10x=p1&A!zKZv|fu7Q{%;le>Pe*0SR%Qlrh zh0@JG;3^_!l?&pFnRb7gwj`X2k(xLJ_bTG{#maO@q3lRVC$|fuu_b{N(P{V7?wtwC zNvsE`6y2r?Pj2yGw^fd=I?@ykPK09Mwwz(J+%dP7BB8y>({7nG%22%?=#<8$K>)JC zK>zKJoS60Vg(o-enTA`s3DkBqK7knYY@FUUS_AIEWLkY+^eiq?z)SM4!6 z`}jDK665|kzFGiG-Cj^bZHl)bZ8)a-&_N3}Joc^WAXWvneTgaGbkx51=3V_QgWV8~ z3@?}Enq}XsK7ZBX_jrFlfuDY_y36l7iM%P?-z4YnqQ#rO*o$k!N>Zu^$VJtH%1 zc#^J%El=1NboMKH21J{=JaRQtXi;T0^0}FT{5fxv-TS5OT@1^0ixz@}ecLOW=s!Bp zLpTvo3lrOZAhQpjJ@xMv(52l!xdLC~-vsm?Ca{r}eH2*)k9=hij_T!-T@eIds+P&R2_qK(BoKnn{jl}A-)3T2@@i{;}PC?Ow+Sq;z?ZcoCr}X7GAiDc|??C75xTH8I z&3%`G3+wbJ?#3FijBpXLB9vLdT}MWKLb@S0>1~eCF~VAug2>Ixa&yl(^6tu>7(NX7 zQ3#?ULvU%){(JHP>yBrzPTDg6s}~jx&$AfF{Lc47Kt~$NH!vDOW^=dZ*nLW2)V*X29%>$a74>T)F5q*Ub=P_CeBLNl2d@JscV&W3Ow%CD5oA?S-ZLHO6%kdL_Bkqnk7>N zpTyln%+rk-+GI;3l#!lebjztpmCWeq{`il><;i<6Klj{_3OJI>v@!vN{+<4mcXCZX z24*!E)fRDY07vV>qFUj$1@Vy7ONJPsV8cX}F{0Ho(X~gmnNla@no&DqtX=qbz85b5lRryG_HKpj z>#@G*R+KR*X_vO2i>lO!p;7V1wI2F2G_>Q_W3NYmlC29S(-3NB8C`5H>RJj9eibE2 zVp5=P1D~hx?&gi5b2LXANj6_(=5GUvax@|RNQz4zfE3xkHsHJNk{Iy}bUy+QCUiXH z<@)1_GA{KUjGu+|`nd?H$>;Q@3V{vQK#t*01lgcsXhD0RPBQV%!J3(pW|VLe;^p!* zq5TIBg@E1OJt$|-Gq9i4WC;@7grOo7aIA0VYMZgILssW@!6$z|uI7V@tvX+*)5Ff+ z8=@aZ>3~C?-#9{kT$O}7E6k54oN{1 zcq@pb|Ak(y30&pf21xU~%N$6vqePpX0=6x`KrO2HH!HgWapa_R!P}uBp$0T(>+cgA z)0{_QQ)<89gqS@-(CGkwIFBl$uaou?J;pn8H5E%N?3=d?eL1NkB8MN>SB*p?{tUxN zgj1DSh?92Wn;*nMI>GTEhgs`(xynh{CmxJlpKN5^^q|ub4IP+GYGeYNh2)uiP@d;P`}4HurdAvI2krza^HGLVn9L)3a2#3F~@08RED zc$6aNk7_{~)j-5mpb^LSF|sbN%T#XxWjwZ4n9FN|F|%|TM$#Tv7|d5j zXL6v-MK@~ovk7&I^=cW2v<=rH=3AGPic zhFCQkExb;KV-~~5c(tnSIgo$(4>@F3c>m1&R{kTYG@PHjXUR;i9=(ZbX$FCM-md zC<$XzPi`Zb<##t{QNWa3;Pf_^JVeHnD#nRF5Qlblx^tFx~>(sXOG< z(8D$ElK5Sp&q*~ubhA2ilk?I{&hB)j=Z~Ga@;J$iHcasug zthY|oy5sIdnl4xVrS>7=jxjK$)+;7iQEsWR9;%BU;MiBAnX`J4^6YTcMc%l$I&t-;t?zS8kyo~tUj3m=q^XP>NcEm&u5SZC*y z@vN!o-(Q)UCW{A6*N)>;@7o%9>ZGWAjQf{-fK{Wy$1P3P9Nd`d(Njd)=-DLf|s8L?Q48{zI+^5VrK zfxQ{?ka!jSrKhS;vx%3J4b8x9%B-sNlsHd-Co5Cwm6>%Srfyc;Isk(| z#cA*q$W)>k2aP<{$;8c@Pfzu6Ixb2R#JX-E8{J7eWxb{Ezt6Vvh23yNKV|dv!EU;* zpRyhr@j$)#cFC}o3H8veSI@Yy z7c;Y4@FWW3disLhxOr8iA$WPGa1K@T+80W1!ph$8_40T?qq;AoZzFs3+hn9DpivhrQ+(7!ZL&rQ73YMG52#kkl@XeLKNWaqt*K*& zob3bYNB3U)e)Rsw;J3O#Q-#W)tJo(Ls4eQ8JrV zgWQ1+I71HTi!JRwJv_FdGr3aR)0d#T`QZF;1`<1*!u)LAjAlXmpy}fZMns}s-2#xK zmTJ{t7drl)61n-;th@~)-MQRjxz@0pL%DZO2{LhZnidsbo_a!1oBFvb5p+s|ggdOb zUX#^pS>r6td3?>a*04K`q;Ad#a&GQ`x;Xj?E%8q0s+y+Kb=qX*Mv7`&jQ8(q;QX|i zAtyw-v*mBe($H}oxo7SHDq&>;O(Ts6UB?zr=+dMZ&eXI^8?xfJ0MZz}w}z>2h`s!t zi_h=-G005*^SD^L%WM6>{~H^01C6Ou39hH5evpq6`ZqXzv#^~!CE@fTi9)n^~fXuuZjkw%F%n!jlX|5%i_2v z$9Rv7-YWEl9-l4By08F4?%L320&!XnLgJQCBhzcl3zq~wC(0Hw#_5|{M3 zECl3hb@`NKV}9YHzt~I90T{+1?Mc8feIr665Z?&S#V|9E?9T1w3^93i`sMD-HhUf< z%KW?KJg*~e*M#d=n2dpQ_}7SyB9gg`ic@dISuM8+9r7v_-MDj`rRVG{#30beuE7GCO^QB8(oYhLi_DH!Ji}gp_>fA7MKJJveVj zY_iRY!+wI}W8?@QJ&bCe*-)w*dNXVm;oQ-APpHR?*IC2KV;MnnPqt!NKsL|D#w;O} z_~3Q*_+U|^-^gYKg4b@2;PZ>&opz-^i2PA)?7(@X6Ix z4*=ZOBGs?w`^rL21C8Gps^c%(5H-C~u=nq2K!)u?t~irJ<4oogEG3HWE4Jlj>_2ePEr5gsCx-LO5Jz>MZ4)o{~CXT7q9nF zvw?asmke0J3mpRjv0;IqQ*dpy?F-s7l6#3PcG@}fTCcp*C^kjdA*_%oI_4jMsf>Ug zdVsd3o@HaqQ)nLl*o=oqq%>mI^sW z0R;Zy`F0HT!mtY_XMw#sWbdYyIG6lFm&)Q@8z zeX|u49woEjpr4vXWP(cjB)}AT@|8o4yrsR=htJ!XCHU;~-<|&t8*(Qe)wwcFa<}L+ zqN($|mW`5hBV1&cI_zl`g_Og?HNtbpv7aR)lLE!lvK#mp=L9>X&h)PsT%W`jN$yW0 z8)3u5CT2Ik&l^S6Grn96SsGI0_xo?BcFUSoBts<)ezhn;ow6LXbHq&U+1GM>>KQI` z3;A1R_za`(kwtuW!;GHsfRnWIT=UtP95I+3U@7xO=wBPlifPHqo-KIP?u zxbz1P^dpJ<1IuGm$MQ;+Ki!~A^THq?Q(bX^Ic-mH@vcHy@EMHMVfHkBZo|au-M@LqJ)A97j(|LugkrkW|P;l_Z+QLjJ*k#5s0h|eDS z26^!+D0x~&RgxzmK|9Al-x60(`NoDRt2YdZS12e({gkPxv27@cCmi$o+kNqH4)W+> zfk2K~OPoW1e6Q2cElTQZbx8eZb`(11Pab`(6;qo7 z)-0)yPAS6;GRf2(=Y*`s{Y}9n>FCjRWgJMu9L^}(!cnkCR8Og1aB_C03PD$I+@7b5 zpC`bdZ_jptKwa8bnaKJCA2j1}XTaOCKUh@*QgX*Vo`KVEt$EWlQiX=07XVIgE#-4H zN6F0%*apMsPd*=Fl%T}cB@a1ohyO~yMJf3X`@}0S|798L*b{a&tRXYXvCTjv2@K~1 zV>!BdWj-bnKzq2B6e-UfB0~@aI7jw5#cuffE)A+1hD3*WCVAd3Bq}nADM>FTEJVfGR`6tx<&U&4}IW1 zt0(9682`{DPr665@Ning2q$GC{r1pQ_C`mzGAjakl1-!(B z`Y%bl5YC4yu3W}S-Jt~w^dxNNpyyp$QK+DoK0gtSmq@{LQrKuYdyW8a>%= zsL@s9!)#*4;s`dg0c9wiD_sBU2Iuw#9Q{yC&okIs+(iBWDu}{0U_Z42UNEVjoYFA9AY__(9UaYluIrGIG+>}{r-#y z`wmZ%iRZ3!lIExBT4iI%%7Qn!+5c)-YpgZGx^p(u$NcqV@M5p%UIlZ4%?f$ud zh$0pGi$Q~fCO(vOFONlW4u5a-wx_F6|k5Q-GxAMOkq(J7|y`7-GkyV^O_}9Pe)IyWF5LuF* zzC|AYm5)AcDQ($laazk_FOva?7%6;92*U8#@PLxAGxMafv7|XIWH;$y<7Eg0uJpyR zBqk)YgXTG&OLJJm;zB^0Ou!8C@WcOM4V;e|gm9Mq^*KG;51@@z*%AR` zZO$QUelQg6Nx5fu2!Cjhs9_S~RAHXLLEB@0;Z~|N0+|+dSdru{#pEf%p9JCvz!gRk zl*|2rG+cPFkhR;fagi$q3yN`i4u&K^@TjZ-Gf<@JJMet~Wej~u`GvOI$}gkMuHaag z5cf7#gnv5P*lD;Cn>*qm=QY$`xDaRN8~#-AdbCjM$fW^BH>|uBgTz}}Q-<_WIn9NH^3?^;UIXJXd2 zVJkY+6Jn59{=h{^CQN%I`QXO0Tjq+RuCf-IaetBAEFRvoOFjDuv!mT!*0p_GH1FxKL2czC zUih=^wC<6J0j&uB<`r|CaWQ;Z+L6Vjxbti-NY8?p%!y0RSU46pF~YKy^rNPO>FPQ2 z%LECwptHde1^u6(Kx45Eq|1`J38Zd0RC)AW$#Sp`J8e1SOy%D7WxhLZE`RNs|8 z!JoX5KkzDi?%uK@cAhJKF3!ZD^5@et6ZLyD@7NmAiwm!60`QDCKubv8e#^_M?U^BE za_PfGNDx9WwVUXr?Eh60aNctUIG@Q~{^^oO6MJ?lPGUFvuv)cGYTbls;T<`Bw=`+7 z|2F2hPr#Ns>1z~&*|W2hg59e0X#ODP?81rmUypt#lYP&8uMQo^n$f*=t49>tEEzrj znhCv;iy{9CH!Cw@dZi9)3vx&Fk2kKQV{)a^wcc25WnvN|sO8ySN<6P*sS-PkJsNg) z&7hZfT{-ic?760%nM!D6#NGcx5_DU*Z5s;Op5a;~?*2sS+YF+nP>tP+%p&eeB(5U9 zfrD9}AKJRBYKzGnPh-#*EZ`wxkJC5^zh#l7#=KWB>Q|5X95*EXGwgwKYN>VDhtU*A z=it;6*^M`&LqD!$a=zbsNI=lW-%(!Hy(>-m@IYRvpQtuVUSaIa=d3oCJI3xVN|~Rr z+fg3OCg$#LY@NrtOrD>;Y}HdG**jlKF>tvI3{a_Vwm6=gwmvWrvUFk?xH=V)L2m?3 zp{kK^HNQ~<31aMTwFx&$f)kEequ6@W+)bMf#T;h0t%sb1aKAH~@2*?s5K=U*w4?*s z?s7fR2=ga<2Y&;p%9U;}ld0!2YxIvUA%`fbTTxiLbTj5rJ#+K+P`c;DET)hwqgVtq znOdvRzG(xPfy<+_0NkJyBxG+P{&~|%p@|gj1o~T*IzCk2$-Y{$#Qb*=m0;ni&8kW! zCfQO{jm)}y7alor*46H9MJXLUIpmW2SV(ndOx==@Nh@7hpVj(zAFH&H1VypEJ=erF zzaEH{PbLOl`EYP)D_*+~3k|_M1KNq*7KB-}bp*)mul?w@)aB{}8ZP3pWUc@$zNI$g z{^~_ek++U3wfyrjb{#@_eM-nC+XG5GXHz{Es~Yih6$?g7zuZmOImOhvoj#8Z@V)y) ztV*|Y6(32<4mw&yM78y9aBqAI)p*$&7;$f@V?8VGtaGE{wDkJ27_cKW=;+FJ2d;&c zjH?*G{e%j7T;tIrQ9!y7exITem2ER5^+bxB%M+Q6qqjB2qX-%GnuRITt%l}z4VOh0 z^nVfp6VHDV!gMTJ!~Z8CNRz9_*Oguegsa)H{R35%9Qe!tbeJ9rVaU$ECzt=!3@-J{ zfdl6xWBY|Jw3s5BPMCI^d@DsxI)ZNW$RN7wr@;y*Z!l1A!}h0;HLx!=5Bc5DX)TCE zHmqnYa9-^&p*LFha8yy1H<0dU^S(${AM&^=nN13&!-?Vt$jE`y06<66ay6h0l(^V_ zI|AoRrXiO8=O1X<{-1xqaRF(T5d(#wL1&bHzY1neG-8`yf5wW|tvXWIDjpIl()W`$?Ad%x)c&fZ78)IKqBg zq1>>}a>J!hnd55g`bOsCW*3y+A7#;vB@75ouRXC`;+R){Do_ZlZEaaY($rirN+{Po zw=%#`wa-$+9#hb>QMU3brwH%dfemHjtNvwK(Hgcq+M=gY>Tc}^N*`wp=XhQ3LkKc+ znz8tnz2%#&zijgl08an81zi|Ljn2xJdJ;G@t*v3F{+my!=erBUQ#&GfZdwq(tYfS- z0VoOLY1b8s6_j{iMK|@>?TiU^m!pkx{$BHeqU!L33hu49lsQ)6mAD#|QOO;{8=gB7 zLvFR@k)f@oPfhS(`>^vaR;#g2BxlUhG5T6*SKM#GDi+7mgP_6_hA5(b5i6fV#LpE@ zpGHb+0M!1k1a<)EFTcTjUpwcTFRi;fignc;?NjG{y`>D^MY;6@MJ4bh@{^e6xL);| zEy`Rgv4UfsJnI!1*x$B7x5RZAY8&?P5U;LAvY!sYe-QyMo96t6NS8~ykZA1LBHcNV zt*ehS3~jwJv9%xVO1SzmuET1jWfmy7FnP8r!H%Wt*RO_H#CkhL!p#Q6TL_uCJiSJ4 zvWO#PJ__rgt{k(WU9??Ae?+~9Fpmdl#!s85VL<}2l*lP5`9;B{B6`nv4d5kqCk+z^ zv+4R(WCSSgfKpZXaYu#UAiec)PyxWaz`J3G<^oQuD+sPpm1ROvoHNM%iCT!i$UsE* z_F#%`9sAkuG)ia-)EGgl26%d-V@u9S*8A=a-Gv+=Xes>Q*PvnMnB*R!nkXEsKNzKq z{6msW&4Jm$_X*$0X`T2N0xMq zMgo_Bbc@4n@$1oJi@2~jY(yxCLaK!r@CJaisg0t`$R(4^wcNzF(s^J5`isr| zr5yg{X}?&!kCj5s#9Uyz`|N2;6KetXff*qg${hgJMR-n;^&!fYAde*1Pi+e3_DbAZ zh;)*#A9W$)nj=ck<&iTOp(GR(J#tP z;E${!CadaD2uJ&Ii#CX=aGJtsVU^kj3Oo##ao$8%&phNA{PJMN{ba=ZE2skyFOr00 z6S0ROz*o`xXK@aFXz90yJN@V}kLumVc;YGzRBRpr;A0sKWE0IDVZ}N_Sw%|k8jtUJ z+JferNP6wfHN}{MrJwLXnSfG(Vsw6SR35*RfJK@h8X_LRG~|rGD&egnt*=k(62km( z{BU|yJ{F&Ur{u>KkN?l7-z7HM({5KU3fPLlA^#xQkIVZcz29H_pXaAucXyRzR+bot zzdeT^$7ol-@I%MHkL9gPDY{bIk7i2t1zW{G%uoy6A6jB}75?Jq7n23Q5(UAu-S04< z$MGJHR5mhSEsUb%e1i?pxM`rj4wTw1>;foa8`yqDMut%n)R#RM9P4$+_D%(JZ z0j=oAeBqqt(00q?r6If9x98PoLNaE{pZALTS8iv=ua|El(U}Zmx2EO#5ckQjoGx`(p|KA6TCoeGhFLTvib(#7!@Ktsn+ObFM z+Ip$yEVjZIWtItB`AutUi1w-(mZD~(^b!HQkHbIgB3a|BC*^evq&>~8waJVG=w+Mt2A@ za#ZN5-Onht3L(kKOzuTTNp?0{(vM0Vk@AcVg4K0pt{d4R3pOv_bixEvKZz1j)>(WQ zOZaEc& z6$nGWJkM~zeki(@!VKh0mamgIj`)e@nFnwW8dru(4~-R5LbFn*`|ao_tUxEZnbIBkh&usJLbTw({jf2aGcWejXl`|Mebk15q) zMY1r;gT(8A&)rtUYq*=Bt&9)?)bHm|H~OU7@F8+dPBOQq*_iyuaIf2UkqdwjoWX-` P-FA98J-%L+zpeit!Vn50 diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py index 8adcea73e25d..558c8aab67c5 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.25.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py index 8adcea73e25d..558c8aab67c5 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.25.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py index 8adcea73e25d..558c8aab67c5 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.25.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/noxfile.py b/packages/google-cloud-datacatalog/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-datacatalog/noxfile.py +++ b/packages/google-cloud-datacatalog/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json index fcb5ceeba367..e1bfcdcf1b01 100644 --- a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json +++ b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datacatalog", - "version": "3.25.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json index 41a5bcc96bc5..f2e225c6cf60 100644 --- a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json +++ b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datacatalog", - "version": "3.25.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-datacatalog/setup.py b/packages/google-cloud-datacatalog/setup.py index 49aa21add2e6..1358d99576ff 100644 --- a/packages/google-cloud-datacatalog/setup.py +++ b/packages/google-cloud-datacatalog/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datacatalog" diff --git a/packages/google-cloud-datacatalog/testing/constraints-3.7.txt b/packages/google-cloud-datacatalog/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-datacatalog/testing/constraints-3.7.txt +++ b/packages/google-cloud-datacatalog/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-dataform/README.rst b/packages/google-cloud-dataform/README.rst index 3284e5014b31..ba4639b76898 100644 --- a/packages/google-cloud-dataform/README.rst +++ b/packages/google-cloud-dataform/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Dataform.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Dataform.: https://cloud.google.com -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py b/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py index 35c9af734238..558c8aab67c5 100644 --- a/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py +++ b/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py b/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py index 35c9af734238..558c8aab67c5 100644 --- a/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py +++ b/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataform/noxfile.py b/packages/google-cloud-dataform/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-dataform/noxfile.py +++ b/packages/google-cloud-dataform/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json b/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json index aa3ca5579d41..1a184ef105a8 100644 --- a/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json +++ b/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataform", - "version": "0.5.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataform/setup.py b/packages/google-cloud-dataform/setup.py index 10a4d943e42e..2e62372a4b7c 100644 --- a/packages/google-cloud-dataform/setup.py +++ b/packages/google-cloud-dataform/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataform" diff --git a/packages/google-cloud-dataform/testing/constraints-3.7.txt b/packages/google-cloud-dataform/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-dataform/testing/constraints-3.7.txt +++ b/packages/google-cloud-dataform/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-dataplex/README.rst b/packages/google-cloud-dataplex/README.rst index 4b0f591216f8..b67c0521939d 100644 --- a/packages/google-cloud-dataplex/README.rst +++ b/packages/google-cloud-dataplex/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Dataplex.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Dataplex.: https://cloud.google.com/dataplex -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py b/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py index ca5dce14d55e..558c8aab67c5 100644 --- a/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py +++ b/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.7.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py b/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py index ca5dce14d55e..558c8aab67c5 100644 --- a/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py +++ b/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.7.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataplex/noxfile.py b/packages/google-cloud-dataplex/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-dataplex/noxfile.py +++ b/packages/google-cloud-dataplex/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json b/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json index 8feb828ded6f..ad778f70e58f 100644 --- a/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json +++ b/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataplex", - "version": "2.7.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataplex/setup.py b/packages/google-cloud-dataplex/setup.py index 6dd8e6086602..0616ca6e6b60 100644 --- a/packages/google-cloud-dataplex/setup.py +++ b/packages/google-cloud-dataplex/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataplex" diff --git a/packages/google-cloud-dataplex/testing/constraints-3.7.txt b/packages/google-cloud-dataplex/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-dataplex/testing/constraints-3.7.txt +++ b/packages/google-cloud-dataplex/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-dataproc-metastore/README.rst b/packages/google-cloud-dataproc-metastore/README.rst index 3478c7f708b5..efd8ed40b151 100644 --- a/packages/google-cloud-dataproc-metastore/README.rst +++ b/packages/google-cloud-dataproc-metastore/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Dataproc Metastore.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Dataproc Metastore.: https://cloud.google.com/dataproc-metastore/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py index 8099b154e9b6..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/noxfile.py b/packages/google-cloud-dataproc-metastore/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-dataproc-metastore/noxfile.py +++ b/packages/google-cloud-dataproc-metastore/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json index 6ea79e87e08b..a1409ff0b020 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "1.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json index 7e80e6e9d558..2e7667ce048f 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "1.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json index 0e1da19d5308..8f741b2fab3f 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "1.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/setup.py b/packages/google-cloud-dataproc-metastore/setup.py index c3ae21177f4f..75bd903b4f02 100644 --- a/packages/google-cloud-dataproc-metastore/setup.py +++ b/packages/google-cloud-dataproc-metastore/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc-metastore" diff --git a/packages/google-cloud-dataproc-metastore/testing/constraints-3.7.txt b/packages/google-cloud-dataproc-metastore/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-dataproc-metastore/testing/constraints-3.7.txt +++ b/packages/google-cloud-dataproc-metastore/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-dataproc/README.rst b/packages/google-cloud-dataproc/README.rst index 3e8ccf1b5397..abce62a13840 100644 --- a/packages/google-cloud-dataproc/README.rst +++ b/packages/google-cloud-dataproc/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Dataproc.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Dataproc.: https://cloud.google.com/dataproc -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py b/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py index 769d6a06054c..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py +++ b/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "5.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py b/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py index 769d6a06054c..558c8aab67c5 100644 --- a/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py +++ b/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "5.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc/noxfile.py b/packages/google-cloud-dataproc/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-dataproc/noxfile.py +++ b/packages/google-cloud-dataproc/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json b/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json index 15126da08c8b..0b7171f0c4e8 100644 --- a/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json +++ b/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc", - "version": "5.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc/setup.py b/packages/google-cloud-dataproc/setup.py index fa0f5e24b572..9dd93798034e 100644 --- a/packages/google-cloud-dataproc/setup.py +++ b/packages/google-cloud-dataproc/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc" diff --git a/packages/google-cloud-dataproc/testing/constraints-3.7.txt b/packages/google-cloud-dataproc/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-dataproc/testing/constraints-3.7.txt +++ b/packages/google-cloud-dataproc/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-datastream/README.rst b/packages/google-cloud-datastream/README.rst index f627fdf2f3c2..53ed0539b337 100644 --- a/packages/google-cloud-datastream/README.rst +++ b/packages/google-cloud-datastream/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Datastream.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Datastream.: https://cloud.google.com/datastream/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/noxfile.py b/packages/google-cloud-datastream/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-datastream/noxfile.py +++ b/packages/google-cloud-datastream/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json index ff0238514ddc..c35515ccf4ca 100644 --- a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json +++ b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datastream", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json index e19a39148c04..8ecc74dc7276 100644 --- a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json +++ b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datastream", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-datastream/setup.py b/packages/google-cloud-datastream/setup.py index f9a54ed4102d..4406e2cf36f3 100644 --- a/packages/google-cloud-datastream/setup.py +++ b/packages/google-cloud-datastream/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datastream" diff --git a/packages/google-cloud-datastream/testing/constraints-3.7.txt b/packages/google-cloud-datastream/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-datastream/testing/constraints-3.7.txt +++ b/packages/google-cloud-datastream/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-deploy/README.rst b/packages/google-cloud-deploy/README.rst index 2ae53f408a8a..9143d65f6a9b 100644 --- a/packages/google-cloud-deploy/README.rst +++ b/packages/google-cloud-deploy/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Deploy.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Deploy.: https://cloud.google.com/deploy/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py b/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py index 14799a6aa533..558c8aab67c5 100644 --- a/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py +++ b/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.6.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py b/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py index 14799a6aa533..558c8aab67c5 100644 --- a/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py +++ b/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.6.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-deploy/noxfile.py b/packages/google-cloud-deploy/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-deploy/noxfile.py +++ b/packages/google-cloud-deploy/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json b/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json index c24aac9f2e10..c29c8f123304 100644 --- a/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json +++ b/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-deploy", - "version": "2.6.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-deploy/setup.py b/packages/google-cloud-deploy/setup.py index 284c0faf90a2..3c9624d83bc4 100644 --- a/packages/google-cloud-deploy/setup.py +++ b/packages/google-cloud-deploy/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-deploy" diff --git a/packages/google-cloud-deploy/testing/constraints-3.7.txt b/packages/google-cloud-deploy/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-deploy/testing/constraints-3.7.txt +++ b/packages/google-cloud-deploy/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-dms/README.rst b/packages/google-cloud-dms/README.rst index 7fe88d5de58b..a2e1639cbaf1 100644 --- a/packages/google-cloud-dms/README.rst +++ b/packages/google-cloud-dms/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Database Migration Service.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Database Migration Service.: https://cloud.google.com/database-migration/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py b/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py index 739fdfae141c..558c8aab67c5 100644 --- a/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py +++ b/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.12.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py b/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py index 739fdfae141c..558c8aab67c5 100644 --- a/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py +++ b/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.12.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-dms/noxfile.py b/packages/google-cloud-dms/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-dms/noxfile.py +++ b/packages/google-cloud-dms/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json b/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json index d03d6fd9b3de..c26f7e5a0532 100644 --- a/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json +++ b/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dms", - "version": "1.12.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-dms/setup.py b/packages/google-cloud-dms/setup.py index bae3f590f004..c0deeb479a24 100644 --- a/packages/google-cloud-dms/setup.py +++ b/packages/google-cloud-dms/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dms" diff --git a/packages/google-cloud-dms/testing/constraints-3.7.txt b/packages/google-cloud-dms/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-dms/testing/constraints-3.7.txt +++ b/packages/google-cloud-dms/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-eventarc/README.rst b/packages/google-cloud-eventarc/README.rst index 18e38e400082..ea2d5c845003 100644 --- a/packages/google-cloud-eventarc/README.rst +++ b/packages/google-cloud-eventarc/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Eventarc.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Eventarc.: https://cloud.google.com/eventarc/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py b/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py index cf18a472a8a2..558c8aab67c5 100644 --- a/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py +++ b/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.15.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py b/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py index cf18a472a8a2..558c8aab67c5 100644 --- a/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py +++ b/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.15.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-eventarc/noxfile.py b/packages/google-cloud-eventarc/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-eventarc/noxfile.py +++ b/packages/google-cloud-eventarc/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json b/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json index 0c4167f3cfdb..73d35229f306 100644 --- a/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json +++ b/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-eventarc", - "version": "1.15.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-eventarc/setup.py b/packages/google-cloud-eventarc/setup.py index f6dd8253e2b8..79cd2e8d18b7 100644 --- a/packages/google-cloud-eventarc/setup.py +++ b/packages/google-cloud-eventarc/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-eventarc" diff --git a/packages/google-cloud-eventarc/testing/constraints-3.7.txt b/packages/google-cloud-eventarc/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-eventarc/testing/constraints-3.7.txt +++ b/packages/google-cloud-eventarc/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-functions/README.rst b/packages/google-cloud-functions/README.rst index 4d9d6341e69d..11cb72f318cb 100644 --- a/packages/google-cloud-functions/README.rst +++ b/packages/google-cloud-functions/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Functions.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Functions.: https://cloud.google.com/functions/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-functions/google/cloud/functions/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions/gapic_version.py index c8ba2b4c6a4f..558c8aab67c5 100644 --- a/packages/google-cloud-functions/google/cloud/functions/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py index c8ba2b4c6a4f..558c8aab67c5 100644 --- a/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py index c8ba2b4c6a4f..558c8aab67c5 100644 --- a/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-functions/noxfile.py b/packages/google-cloud-functions/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-functions/noxfile.py +++ b/packages/google-cloud-functions/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json index 51c2aa20b98a..7051120dab3b 100644 --- a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json +++ b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-functions", - "version": "1.20.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json index ad3141327543..eea3a0edf2a1 100644 --- a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json +++ b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-functions", - "version": "1.20.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-functions/setup.py b/packages/google-cloud-functions/setup.py index 4ff91ff458ee..5d3bea65ed55 100644 --- a/packages/google-cloud-functions/setup.py +++ b/packages/google-cloud-functions/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-functions" diff --git a/packages/google-cloud-functions/testing/constraints-3.7.txt b/packages/google-cloud-functions/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-functions/testing/constraints-3.7.txt +++ b/packages/google-cloud-functions/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-gke-backup/README.rst b/packages/google-cloud-gke-backup/README.rst index a872ffbceade..56adb37f2a4c 100644 --- a/packages/google-cloud-gke-backup/README.rst +++ b/packages/google-cloud-gke-backup/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Backup for GKE.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Backup for GKE.: https://cloud.google.com/kubernetes-engine/docs/add-on/backup-for-gke/concepts/backup-for-gke -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py b/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py index 35c9af734238..558c8aab67c5 100644 --- a/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py +++ b/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py b/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py index 35c9af734238..558c8aab67c5 100644 --- a/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py +++ b/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-backup/noxfile.py b/packages/google-cloud-gke-backup/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-gke-backup/noxfile.py +++ b/packages/google-cloud-gke-backup/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json b/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json index 3acaeae1c152..ae88d4785854 100644 --- a/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json +++ b/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-backup", - "version": "0.5.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-gke-backup/setup.py b/packages/google-cloud-gke-backup/setup.py index 05f5fe816d3e..614e8153b3b9 100644 --- a/packages/google-cloud-gke-backup/setup.py +++ b/packages/google-cloud-gke-backup/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-backup" diff --git a/packages/google-cloud-gke-backup/testing/constraints-3.7.txt b/packages/google-cloud-gke-backup/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-gke-backup/testing/constraints-3.7.txt +++ b/packages/google-cloud-gke-backup/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-gke-hub/README.rst b/packages/google-cloud-gke-hub/README.rst index 68ca60d39f0f..c9a4326577c0 100644 --- a/packages/google-cloud-gke-hub/README.rst +++ b/packages/google-cloud-gke-hub/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the GKE Hub.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the GKE Hub.: https://cloud.google.com/anthos/gke/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py index 007d6040cbe0..558c8aab67c5 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py index 007d6040cbe0..558c8aab67c5 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py index 007d6040cbe0..558c8aab67c5 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py index 007d6040cbe0..558c8aab67c5 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py index 007d6040cbe0..558c8aab67c5 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/noxfile.py b/packages/google-cloud-gke-hub/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-gke-hub/noxfile.py +++ b/packages/google-cloud-gke-hub/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json index 793370c23006..0e22653d9aa3 100644 --- a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json +++ b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-hub", - "version": "1.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json index f68b495fcd01..c8aed2f9f17d 100644 --- a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json +++ b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-hub", - "version": "1.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iam-logging/README.rst b/packages/google-cloud-iam-logging/README.rst index dcab319d2d81..c13f44da9b37 100644 --- a/packages/google-cloud-iam-logging/README.rst +++ b/packages/google-cloud-iam-logging/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the IAM Logging Protos.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the IAM Logging Protos.: https://cloud.google.com/iam/docs/audit-logging -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-iam-logging/noxfile.py b/packages/google-cloud-iam-logging/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-iam-logging/noxfile.py +++ b/packages/google-cloud-iam-logging/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-iam-logging/setup.py b/packages/google-cloud-iam-logging/setup.py index aad305b8ebb5..e4aed6f34847 100644 --- a/packages/google-cloud-iam-logging/setup.py +++ b/packages/google-cloud-iam-logging/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iam-logging" diff --git a/packages/google-cloud-iam-logging/testing/constraints-3.7.txt b/packages/google-cloud-iam-logging/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-iam-logging/testing/constraints-3.7.txt +++ b/packages/google-cloud-iam-logging/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-iam/README.rst b/packages/google-cloud-iam/README.rst index b3bf82cdfd32..8d40a37a5d48 100644 --- a/packages/google-cloud-iam/README.rst +++ b/packages/google-cloud-iam/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Identity and Access Management.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Identity and Access Management.: https://cloud.google.com/iam/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-iam/google/cloud/iam/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py index 1074c4de1723..558c8aab67c5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.18.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iam/noxfile.py b/packages/google-cloud-iam/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-iam/noxfile.py +++ b/packages/google-cloud-iam/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json index 192b430ca62a..0fa605b91500 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "2.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json index df1a76d87a7b..0809777f1998 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "2.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json index ec3fa5534d89..5b79ae802abe 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "2.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json index 8247dcabe73c..5b3b08a7e2fc 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "2.18.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iap/README.rst b/packages/google-cloud-iap/README.rst index e4dae9a997e9..428ee30b24a6 100644 --- a/packages/google-cloud-iap/README.rst +++ b/packages/google-cloud-iap/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Identity-Aware Proxy.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Identity-Aware Proxy.: https://cloud.google.com/iap -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-iap/google/cloud/iap/gapic_version.py b/packages/google-cloud-iap/google/cloud/iap/gapic_version.py index 3e0ea3b28f0a..558c8aab67c5 100644 --- a/packages/google-cloud-iap/google/cloud/iap/gapic_version.py +++ b/packages/google-cloud-iap/google/cloud/iap/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.16.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py b/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py index 3e0ea3b28f0a..558c8aab67c5 100644 --- a/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py +++ b/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.16.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-iap/noxfile.py b/packages/google-cloud-iap/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-iap/noxfile.py +++ b/packages/google-cloud-iap/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json b/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json index 879911c88b81..e4e6134926e0 100644 --- a/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json +++ b/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iap", - "version": "1.16.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-iap/setup.py b/packages/google-cloud-iap/setup.py index 593ab4fcb944..92daded2d6b0 100644 --- a/packages/google-cloud-iap/setup.py +++ b/packages/google-cloud-iap/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iap" diff --git a/packages/google-cloud-iap/testing/constraints-3.7.txt b/packages/google-cloud-iap/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-iap/testing/constraints-3.7.txt +++ b/packages/google-cloud-iap/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-kms/README.rst b/packages/google-cloud-kms/README.rst index 701c15738344..b8c41bdd2e0b 100644 --- a/packages/google-cloud-kms/README.rst +++ b/packages/google-cloud-kms/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Key Management Service.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Key Management Service.: https://cloud.google.com/kms -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-kms/google/cloud/kms/gapic_version.py b/packages/google-cloud-kms/google/cloud/kms/gapic_version.py index 57b675ccdf88..558c8aab67c5 100644 --- a/packages/google-cloud-kms/google/cloud/kms/gapic_version.py +++ b/packages/google-cloud-kms/google/cloud/kms/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.3.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py b/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py index 57b675ccdf88..558c8aab67c5 100644 --- a/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py +++ b/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.3.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-kms/noxfile.py b/packages/google-cloud-kms/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-kms/noxfile.py +++ b/packages/google-cloud-kms/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json b/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json index a657757ff4e2..31292c269f5b 100644 --- a/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json +++ b/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-kms", - "version": "3.3.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-kms/setup.py b/packages/google-cloud-kms/setup.py index 0e059b5cf3dd..066656211e45 100644 --- a/packages/google-cloud-kms/setup.py +++ b/packages/google-cloud-kms/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms" diff --git a/packages/google-cloud-kms/testing/constraints-3.7.txt b/packages/google-cloud-kms/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-kms/testing/constraints-3.7.txt +++ b/packages/google-cloud-kms/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-network-connectivity/README.rst b/packages/google-cloud-network-connectivity/README.rst index ab925f3165e0..9323e63d446e 100644 --- a/packages/google-cloud-network-connectivity/README.rst +++ b/packages/google-cloud-network-connectivity/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Network Connectivity Center.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Network Connectivity Center.: https://cloud.google.com/network-connectivity/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py index ca5dce14d55e..558c8aab67c5 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.7.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py index ca5dce14d55e..558c8aab67c5 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.7.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py index ca5dce14d55e..558c8aab67c5 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.7.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/noxfile.py b/packages/google-cloud-network-connectivity/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-network-connectivity/noxfile.py +++ b/packages/google-cloud-network-connectivity/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json index 9e8385d0995a..8d620f5c261f 100644 --- a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json +++ b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-connectivity", - "version": "2.7.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json index 3d8c86a25517..780180f11887 100644 --- a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json +++ b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-connectivity", - "version": "2.7.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-connectivity/setup.py b/packages/google-cloud-network-connectivity/setup.py index 0e828d8a37d8..7f66398ca151 100644 --- a/packages/google-cloud-network-connectivity/setup.py +++ b/packages/google-cloud-network-connectivity/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-connectivity" diff --git a/packages/google-cloud-network-connectivity/testing/constraints-3.7.txt b/packages/google-cloud-network-connectivity/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-network-connectivity/testing/constraints-3.7.txt +++ b/packages/google-cloud-network-connectivity/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 From 770cf0f31125586a8622e9639f6d24c1bafa9b31 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:50:33 +0500 Subject: [PATCH 04/13] chore: [Many APIs] Update gapic-generator-python to v1.22.1 (#13524) BEGIN_COMMIT_OVERRIDE chore: Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. fix(deps): Require grpc-google-iam-v1>=0.14.0 PiperOrigin-RevId: 726142856 Source-Link: https://github.com/googleapis/googleapis/commit/25989cb753bf7d69ee446bda9d9794b61912707d Source-Link: https://github.com/googleapis/googleapis-gen/commit/677041b91cef1598cc55727d59a2804b198a5bbf Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmstbWFuYWdlbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmstc2VjdXJpdHkvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmstc2VydmljZXMvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5vdGVib29rcy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBhcmFtZXRlcm1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeS10cm91Ymxlc2hvb3Rlci8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXNpbXVsYXRvci8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXRyb3VibGVzaG9vdGVyLWlhbS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZhdGUtY2EvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlc291cmNlLW1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJ1bi8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3JldC1tYW5hZ2VyLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyZXNvdXJjZW1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6IjY3NzA0MWI5MWNlZjE1OThjYzU1NzI3ZDU5YTI4MDRiMTk4YTViYmYifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5Y2VudGVyLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5Y2VudGVybWFuYWdlbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlcnZpY2UtZGlyZWN0b3J5Ly5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlcnZpY2UtbWFuYWdlbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXRhc2tzLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXRyYW5zbGF0ZS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXZpc2lvbmFpLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= --------- Co-authored-by: Owl Bot --- .../README.rst | 4 +- .../cloud/network_management/gapic_version.py | 2 +- .../network_management_v1/gapic_version.py | 2 +- .../noxfile.py | 81 +- ...ata_google.cloud.networkmanagement.v1.json | 2 +- .../google-cloud-network-management/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-network-security/README.rst | 4 +- .../cloud/network_security/gapic_version.py | 2 +- .../network_security_v1/gapic_version.py | 2 +- .../network_security_v1beta1/gapic_version.py | 2 +- .../google-cloud-network-security/noxfile.py | 81 +- ...adata_google.cloud.networksecurity.v1.json | 2 +- ..._google.cloud.networksecurity.v1beta1.json | 2 +- .../google-cloud-network-security/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-network-services/README.rst | 4 +- .../cloud/network_services/gapic_version.py | 2 +- .../network_services_v1/gapic_version.py | 2 +- .../google-cloud-network-services/noxfile.py | 81 +- ...adata_google.cloud.networkservices.v1.json | 2 +- .../google-cloud-network-services/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-notebooks/README.rst | 4 +- .../google/cloud/notebooks/gapic_version.py | 2 +- .../cloud/notebooks_v1/gapic_version.py | 2 +- .../cloud/notebooks_v1beta1/gapic_version.py | 2 +- .../cloud/notebooks_v2/gapic_version.py | 2 +- packages/google-cloud-notebooks/noxfile.py | 81 +- ...et_metadata_google.cloud.notebooks.v1.json | 2 +- ...tadata_google.cloud.notebooks.v1beta1.json | 2 +- ...et_metadata_google.cloud.notebooks.v2.json | 2 +- packages/google-cloud-notebooks/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-parametermanager/README.rst | 4 +- .../cloud/parametermanager/gapic_version.py | 3 +- .../parametermanager_v1/gapic_version.py | 3 +- .../services/parameter_manager/client.py | 73 +- .../parameter_manager/transports/rest.py | 283 +++++- .../google-cloud-parametermanager/noxfile.py | 81 +- .../test_parameter_manager.py | 108 ++ .../README.rst | 4 +- .../policytroubleshooter/gapic_version.py | 2 +- .../policytroubleshooter_v1/gapic_version.py | 2 +- .../services/iam_checker/client.py | 29 + .../services/iam_checker/transports/rest.py | 33 +- .../noxfile.py | 81 +- ..._google.cloud.policytroubleshooter.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../test_iam_checker.py | 59 ++ .../google-cloud-policysimulator/README.rst | 4 +- .../cloud/policysimulator/gapic_version.py | 2 +- .../cloud/policysimulator_v1/gapic_version.py | 2 +- .../services/simulator/client.py | 73 +- .../services/simulator/transports/rest.py | 95 +- .../google-cloud-policysimulator/noxfile.py | 81 +- ...adata_google.cloud.policysimulator.v1.json | 2 +- .../google-cloud-policysimulator/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../policysimulator_v1/test_simulator.py | 68 ++ .../README.rst | 4 +- .../policytroubleshooter_iam/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../services/policy_troubleshooter/client.py | 29 + .../policy_troubleshooter/transports/rest.py | 34 +- .../noxfile.py | 81 +- ...gle.cloud.policytroubleshooter.iam.v3.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../test_policy_troubleshooter.py | 59 ++ packages/google-cloud-private-ca/README.rst | 4 +- .../cloud/security/privateca/gapic_version.py | 2 +- .../security/privateca_v1/gapic_version.py | 2 +- .../certificate_authority_service/client.py | 183 ++-- .../transports/rest.py | 936 ++++++++++++++++-- .../privateca_v1beta1/gapic_version.py | 2 +- .../certificate_authority_service/client.py | 29 + .../transports/rest.py | 659 +++++++++++- packages/google-cloud-private-ca/noxfile.py | 81 +- ...ta_google.cloud.security.privateca.v1.json | 2 +- ...ogle.cloud.security.privateca.v1beta1.json | 2 +- packages/google-cloud-private-ca/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../test_certificate_authority_service.py | 239 +++++ .../test_certificate_authority_service.py | 185 ++++ .../google-cloud-resource-manager/README.rst | 4 +- .../cloud/resourcemanager/gapic_version.py | 2 +- .../cloud/resourcemanager_v3/gapic_version.py | 2 +- .../services/folders/client.py | 51 +- .../services/folders/transports/rest.py | 344 ++++++- .../services/organizations/client.py | 51 +- .../services/organizations/transports/rest.py | 161 ++- .../services/projects/client.py | 51 +- .../services/projects/transports/rest.py | 346 ++++++- .../services/tag_bindings/client.py | 51 +- .../services/tag_bindings/transports/rest.py | 128 ++- .../services/tag_holds/client.py | 51 +- .../services/tag_holds/transports/rest.py | 93 +- .../services/tag_keys/client.py | 51 +- .../services/tag_keys/transports/rest.py | 282 +++++- .../services/tag_values/client.py | 51 +- .../services/tag_values/transports/rest.py | 284 +++++- .../google-cloud-resource-manager/noxfile.py | 81 +- ...adata_google.cloud.resourcemanager.v3.json | 2 +- .../google-cloud-resource-manager/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../gapic/resourcemanager_v3/test_folders.py | 108 ++ .../resourcemanager_v3/test_organizations.py | 83 ++ .../gapic/resourcemanager_v3/test_projects.py | 108 ++ .../resourcemanager_v3/test_tag_bindings.py | 76 ++ .../resourcemanager_v3/test_tag_holds.py | 65 ++ .../gapic/resourcemanager_v3/test_tag_keys.py | 98 ++ .../resourcemanager_v3/test_tag_values.py | 99 ++ packages/google-cloud-run/README.rst | 4 +- .../google/cloud/run/gapic_version.py | 2 +- .../google/cloud/run_v2/gapic_version.py | 2 +- packages/google-cloud-run/noxfile.py | 81 +- .../snippet_metadata_google.cloud.run.v2.json | 2 +- packages/google-cloud-run/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-secret-manager/README.rst | 4 +- .../cloud/secretmanager/gapic_version.py | 2 +- .../cloud/secretmanager_v1/gapic_version.py | 2 +- .../secretmanager_v1beta1/gapic_version.py | 2 +- .../secretmanager_v1beta2/gapic_version.py | 2 +- .../google-cloud-secret-manager/noxfile.py | 81 +- ...etadata_google.cloud.secretmanager.v1.json | 2 +- ...ta_google.cloud.secretmanager.v1beta2.json | 2 +- ...metadata_google.cloud.secrets.v1beta1.json | 2 +- packages/google-cloud-secret-manager/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../securesourcemanager/gapic_version.py | 2 +- .../securesourcemanager_v1/gapic_version.py | 2 +- .../noxfile.py | 81 +- ...a_google.cloud.securesourcemanager.v1.json | 2 +- .../google-cloud-securesourcemanager/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-securitycenter/README.rst | 4 +- .../cloud/securitycenter/gapic_version.py | 2 +- .../cloud/securitycenter_v1/gapic_version.py | 2 +- .../securitycenter_v1beta1/gapic_version.py | 2 +- .../securitycenter_v1p1beta1/gapic_version.py | 2 +- .../cloud/securitycenter_v2/gapic_version.py | 2 +- .../google-cloud-securitycenter/noxfile.py | 81 +- ...tadata_google.cloud.securitycenter.v1.json | 2 +- ...a_google.cloud.securitycenter.v1beta1.json | 2 +- ...google.cloud.securitycenter.v1p1beta1.json | 2 +- ...tadata_google.cloud.securitycenter.v2.json | 2 +- packages/google-cloud-securitycenter/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../securitycentermanagement/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../noxfile.py | 81 +- ...gle.cloud.securitycentermanagement.v1.json | 2 +- .../setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../google-cloud-service-directory/README.rst | 4 +- .../cloud/servicedirectory/gapic_version.py | 2 +- .../servicedirectory_v1/gapic_version.py | 2 +- .../servicedirectory_v1beta1/gapic_version.py | 2 +- .../google-cloud-service-directory/noxfile.py | 81 +- ...data_google.cloud.servicedirectory.v1.json | 2 +- ...google.cloud.servicedirectory.v1beta1.json | 2 +- .../google-cloud-service-directory/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../README.rst | 4 +- .../cloud/servicemanagement/gapic_version.py | 2 +- .../servicemanagement_v1/gapic_version.py | 2 +- .../noxfile.py | 81 +- ...adata_google.api.servicemanagement.v1.json | 2 +- .../google-cloud-service-management/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- .../test_service_manager.py | 1 + packages/google-cloud-tasks/README.rst | 4 +- .../google/cloud/tasks/gapic_version.py | 2 +- .../google/cloud/tasks_v2/gapic_version.py | 2 +- .../cloud/tasks_v2beta2/gapic_version.py | 2 +- .../cloud/tasks_v2beta3/gapic_version.py | 2 +- packages/google-cloud-tasks/noxfile.py | 81 +- ...nippet_metadata_google.cloud.tasks.v2.json | 2 +- ...t_metadata_google.cloud.tasks.v2beta2.json | 2 +- ...t_metadata_google.cloud.tasks.v2beta3.json | 2 +- packages/google-cloud-tasks/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-translate/README.rst | 4 +- .../google/cloud/translate/gapic_version.py | 2 +- .../cloud/translate_v3/gapic_version.py | 2 +- .../cloud/translate_v3beta1/gapic_version.py | 2 +- packages/google-cloud-translate/noxfile.py | 81 +- ..._metadata_google.cloud.translation.v3.json | 2 +- ...data_google.cloud.translation.v3beta1.json | 2 +- packages/google-cloud-translate/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-visionai/README.rst | 4 +- .../google/cloud/visionai/gapic_version.py | 2 +- .../google/cloud/visionai_v1/gapic_version.py | 2 +- .../cloud/visionai_v1alpha1/gapic_version.py | 2 +- packages/google-cloud-visionai/noxfile.py | 81 +- ...pet_metadata_google.cloud.visionai.v1.json | 2 +- ...tadata_google.cloud.visionai.v1alpha1.json | 2 +- packages/google-cloud-visionai/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- 205 files changed, 7160 insertions(+), 599 deletions(-) diff --git a/packages/google-cloud-network-management/README.rst b/packages/google-cloud-network-management/README.rst index 8210c6ca3072..afde333db9d7 100644 --- a/packages/google-cloud-network-management/README.rst +++ b/packages/google-cloud-network-management/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Network Management.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Network Management.: https://cloud.google.com/network-management -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py b/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py index 547a38985bb7..558c8aab67c5 100644 --- a/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py +++ b/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.25.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py b/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py index 547a38985bb7..558c8aab67c5 100644 --- a/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py +++ b/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.25.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-management/noxfile.py b/packages/google-cloud-network-management/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-network-management/noxfile.py +++ b/packages/google-cloud-network-management/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json b/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json index ac042fddbcea..7bedd05e20b0 100644 --- a/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json +++ b/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-management", - "version": "1.25.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-management/setup.py b/packages/google-cloud-network-management/setup.py index 60447edaac79..6117048e30e0 100644 --- a/packages/google-cloud-network-management/setup.py +++ b/packages/google-cloud-network-management/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-management" diff --git a/packages/google-cloud-network-management/testing/constraints-3.7.txt b/packages/google-cloud-network-management/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-network-management/testing/constraints-3.7.txt +++ b/packages/google-cloud-network-management/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-network-security/README.rst b/packages/google-cloud-network-security/README.rst index 9e689a9c033a..c85f1a74bde0 100644 --- a/packages/google-cloud-network-security/README.rst +++ b/packages/google-cloud-network-security/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Network Security.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Network Security.: https://cloud.google.com/traffic-director/docs/reference/network-security/rest -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py index 956522e5b1bb..558c8aab67c5 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.9.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py index 956522e5b1bb..558c8aab67c5 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.9.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py index 956522e5b1bb..558c8aab67c5 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.9.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/noxfile.py b/packages/google-cloud-network-security/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-network-security/noxfile.py +++ b/packages/google-cloud-network-security/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json index 559109d0c18b..71edaea2e319 100644 --- a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json +++ b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-security", - "version": "0.9.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json index 6cc64388500a..71c9b6489c86 100644 --- a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json +++ b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-security", - "version": "0.9.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-security/setup.py b/packages/google-cloud-network-security/setup.py index d8d37dfe5f6b..c14cf1610823 100644 --- a/packages/google-cloud-network-security/setup.py +++ b/packages/google-cloud-network-security/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-security" diff --git a/packages/google-cloud-network-security/testing/constraints-3.7.txt b/packages/google-cloud-network-security/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-network-security/testing/constraints-3.7.txt +++ b/packages/google-cloud-network-security/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-network-services/README.rst b/packages/google-cloud-network-services/README.rst index 925ef2bc8feb..092ac25694e4 100644 --- a/packages/google-cloud-network-services/README.rst +++ b/packages/google-cloud-network-services/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Network Services.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Network Services.: https://cloud.google.com -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py b/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py index d26af44492c7..558c8aab67c5 100644 --- a/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py +++ b/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.18" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py b/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py index d26af44492c7..558c8aab67c5 100644 --- a/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py +++ b/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.18" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-network-services/noxfile.py b/packages/google-cloud-network-services/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-network-services/noxfile.py +++ b/packages/google-cloud-network-services/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json b/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json index b87e870fdb16..c9caccff1bd4 100644 --- a/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json +++ b/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-services", - "version": "0.5.18" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-network-services/setup.py b/packages/google-cloud-network-services/setup.py index 7aa9d6a38783..6043a32744e1 100644 --- a/packages/google-cloud-network-services/setup.py +++ b/packages/google-cloud-network-services/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-services" diff --git a/packages/google-cloud-network-services/testing/constraints-3.7.txt b/packages/google-cloud-network-services/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-network-services/testing/constraints-3.7.txt +++ b/packages/google-cloud-network-services/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-notebooks/README.rst b/packages/google-cloud-notebooks/README.rst index 552adb66e6b3..4ffe14cef4f4 100644 --- a/packages/google-cloud-notebooks/README.rst +++ b/packages/google-cloud-notebooks/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the AI Platform Notebooks.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the AI Platform Notebooks.: https://cloud.google.com/ai-platform/notebooks/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/noxfile.py b/packages/google-cloud-notebooks/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-notebooks/noxfile.py +++ b/packages/google-cloud-notebooks/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json index 06443536bb5f..220b755f8ced 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json index e52f5b8599f9..508ef241d01c 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json index d9ed1dd193b0..11d18ed44573 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/setup.py b/packages/google-cloud-notebooks/setup.py index 516337184d9b..2b449b7afba5 100644 --- a/packages/google-cloud-notebooks/setup.py +++ b/packages/google-cloud-notebooks/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-notebooks" diff --git a/packages/google-cloud-notebooks/testing/constraints-3.7.txt b/packages/google-cloud-notebooks/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-notebooks/testing/constraints-3.7.txt +++ b/packages/google-cloud-notebooks/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-parametermanager/README.rst b/packages/google-cloud-parametermanager/README.rst index b8240d1b09d6..70fc00ac59ea 100644 --- a/packages/google-cloud-parametermanager/README.rst +++ b/packages/google-cloud-parametermanager/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Parameter Manager API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Parameter Manager API.: https://cloud.google.com/secret-manager/parameter-manager/docs/overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py index 20d1d778beb7..558c8aab67c5 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py @@ -13,5 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # - -__version__ = "0.1.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py index 20d1d778beb7..558c8aab67c5 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py @@ -13,5 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # - -__version__ = "0.1.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/client.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/client.py index ab672811c4ec..0e24b01f5e28 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/client.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -513,6 +515,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2003,16 +2032,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2058,16 +2091,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/transports/rest.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/transports/rest.py index 7b16bef8564b..7ae12f27e942 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/transports/rest.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/services/parameter_manager/transports/rest.py @@ -171,12 +171,35 @@ def pre_create_parameter( def post_create_parameter(self, response: service.Parameter) -> service.Parameter: """Post-rpc interceptor for create_parameter - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_parameter_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_create_parameter` interceptor runs + before the `post_create_parameter_with_metadata` interceptor. """ return response + def post_create_parameter_with_metadata( + self, + response: service.Parameter, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.Parameter, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_parameter + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_create_parameter_with_metadata` + interceptor in new development instead of the `post_create_parameter` interceptor. + When both interceptors are used, this `post_create_parameter_with_metadata` interceptor runs after the + `post_create_parameter` interceptor. The (possibly modified) response returned by + `post_create_parameter` will be passed to + `post_create_parameter_with_metadata`. + """ + return response, metadata + def pre_create_parameter_version( self, request: service.CreateParameterVersionRequest, @@ -196,12 +219,35 @@ def post_create_parameter_version( ) -> service.ParameterVersion: """Post-rpc interceptor for create_parameter_version - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_parameter_version_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_create_parameter_version` interceptor runs + before the `post_create_parameter_version_with_metadata` interceptor. """ return response + def post_create_parameter_version_with_metadata( + self, + response: service.ParameterVersion, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.ParameterVersion, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_parameter_version + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_create_parameter_version_with_metadata` + interceptor in new development instead of the `post_create_parameter_version` interceptor. + When both interceptors are used, this `post_create_parameter_version_with_metadata` interceptor runs after the + `post_create_parameter_version` interceptor. The (possibly modified) response returned by + `post_create_parameter_version` will be passed to + `post_create_parameter_version_with_metadata`. + """ + return response, metadata + def pre_delete_parameter( self, request: service.DeleteParameterRequest, @@ -243,12 +289,35 @@ def pre_get_parameter( def post_get_parameter(self, response: service.Parameter) -> service.Parameter: """Post-rpc interceptor for get_parameter - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_parameter_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_get_parameter` interceptor runs + before the `post_get_parameter_with_metadata` interceptor. """ return response + def post_get_parameter_with_metadata( + self, + response: service.Parameter, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.Parameter, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_parameter + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_get_parameter_with_metadata` + interceptor in new development instead of the `post_get_parameter` interceptor. + When both interceptors are used, this `post_get_parameter_with_metadata` interceptor runs after the + `post_get_parameter` interceptor. The (possibly modified) response returned by + `post_get_parameter` will be passed to + `post_get_parameter_with_metadata`. + """ + return response, metadata + def pre_get_parameter_version( self, request: service.GetParameterVersionRequest, @@ -268,12 +337,35 @@ def post_get_parameter_version( ) -> service.ParameterVersion: """Post-rpc interceptor for get_parameter_version - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_parameter_version_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_get_parameter_version` interceptor runs + before the `post_get_parameter_version_with_metadata` interceptor. """ return response + def post_get_parameter_version_with_metadata( + self, + response: service.ParameterVersion, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.ParameterVersion, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_parameter_version + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_get_parameter_version_with_metadata` + interceptor in new development instead of the `post_get_parameter_version` interceptor. + When both interceptors are used, this `post_get_parameter_version_with_metadata` interceptor runs after the + `post_get_parameter_version` interceptor. The (possibly modified) response returned by + `post_get_parameter_version` will be passed to + `post_get_parameter_version_with_metadata`. + """ + return response, metadata + def pre_list_parameters( self, request: service.ListParametersRequest, @@ -291,12 +383,35 @@ def post_list_parameters( ) -> service.ListParametersResponse: """Post-rpc interceptor for list_parameters - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_parameters_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_list_parameters` interceptor runs + before the `post_list_parameters_with_metadata` interceptor. """ return response + def post_list_parameters_with_metadata( + self, + response: service.ListParametersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.ListParametersResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_parameters + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_list_parameters_with_metadata` + interceptor in new development instead of the `post_list_parameters` interceptor. + When both interceptors are used, this `post_list_parameters_with_metadata` interceptor runs after the + `post_list_parameters` interceptor. The (possibly modified) response returned by + `post_list_parameters` will be passed to + `post_list_parameters_with_metadata`. + """ + return response, metadata + def pre_list_parameter_versions( self, request: service.ListParameterVersionsRequest, @@ -316,12 +431,37 @@ def post_list_parameter_versions( ) -> service.ListParameterVersionsResponse: """Post-rpc interceptor for list_parameter_versions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_parameter_versions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_list_parameter_versions` interceptor runs + before the `post_list_parameter_versions_with_metadata` interceptor. """ return response + def post_list_parameter_versions_with_metadata( + self, + response: service.ListParameterVersionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListParameterVersionsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_parameter_versions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_list_parameter_versions_with_metadata` + interceptor in new development instead of the `post_list_parameter_versions` interceptor. + When both interceptors are used, this `post_list_parameter_versions_with_metadata` interceptor runs after the + `post_list_parameter_versions` interceptor. The (possibly modified) response returned by + `post_list_parameter_versions` will be passed to + `post_list_parameter_versions_with_metadata`. + """ + return response, metadata + def pre_render_parameter_version( self, request: service.RenderParameterVersionRequest, @@ -341,12 +481,37 @@ def post_render_parameter_version( ) -> service.RenderParameterVersionResponse: """Post-rpc interceptor for render_parameter_version - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_render_parameter_version_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_render_parameter_version` interceptor runs + before the `post_render_parameter_version_with_metadata` interceptor. """ return response + def post_render_parameter_version_with_metadata( + self, + response: service.RenderParameterVersionResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.RenderParameterVersionResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for render_parameter_version + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_render_parameter_version_with_metadata` + interceptor in new development instead of the `post_render_parameter_version` interceptor. + When both interceptors are used, this `post_render_parameter_version_with_metadata` interceptor runs after the + `post_render_parameter_version` interceptor. The (possibly modified) response returned by + `post_render_parameter_version` will be passed to + `post_render_parameter_version_with_metadata`. + """ + return response, metadata + def pre_update_parameter( self, request: service.UpdateParameterRequest, @@ -362,12 +527,35 @@ def pre_update_parameter( def post_update_parameter(self, response: service.Parameter) -> service.Parameter: """Post-rpc interceptor for update_parameter - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_parameter_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_update_parameter` interceptor runs + before the `post_update_parameter_with_metadata` interceptor. """ return response + def post_update_parameter_with_metadata( + self, + response: service.Parameter, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.Parameter, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_parameter + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_update_parameter_with_metadata` + interceptor in new development instead of the `post_update_parameter` interceptor. + When both interceptors are used, this `post_update_parameter_with_metadata` interceptor runs after the + `post_update_parameter` interceptor. The (possibly modified) response returned by + `post_update_parameter` will be passed to + `post_update_parameter_with_metadata`. + """ + return response, metadata + def pre_update_parameter_version( self, request: service.UpdateParameterVersionRequest, @@ -387,12 +575,35 @@ def post_update_parameter_version( ) -> service.ParameterVersion: """Post-rpc interceptor for update_parameter_version - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_parameter_version_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ParameterManager server but before - it is returned to user code. + it is returned to user code. This `post_update_parameter_version` interceptor runs + before the `post_update_parameter_version_with_metadata` interceptor. """ return response + def post_update_parameter_version_with_metadata( + self, + response: service.ParameterVersion, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.ParameterVersion, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_parameter_version + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ParameterManager server but before it is returned to user code. + + We recommend only using this `post_update_parameter_version_with_metadata` + interceptor in new development instead of the `post_update_parameter_version` interceptor. + When both interceptors are used, this `post_update_parameter_version_with_metadata` interceptor runs after the + `post_update_parameter_version` interceptor. The (possibly modified) response returned by + `post_update_parameter_version` will be passed to + `post_update_parameter_version_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -656,6 +867,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_parameter(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_parameter_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -810,6 +1025,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_parameter_version(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_parameter_version_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1171,6 +1390,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_parameter(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_parameter_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1317,6 +1540,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_parameter_version(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_parameter_version_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1460,6 +1687,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_parameters(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_parameters_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1608,6 +1839,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_parameter_versions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_parameter_versions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1758,6 +1993,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_render_parameter_version(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_render_parameter_version_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1909,6 +2148,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_parameter(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_parameter_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2063,6 +2306,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_parameter_version(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_parameter_version_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-parametermanager/noxfile.py b/packages/google-cloud-parametermanager/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-parametermanager/noxfile.py +++ b/packages/google-cloud-parametermanager/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-parametermanager/tests/unit/gapic/parametermanager_v1/test_parameter_manager.py b/packages/google-cloud-parametermanager/tests/unit/gapic/parametermanager_v1/test_parameter_manager.py index 77d9d19abadc..aa096467a262 100644 --- a/packages/google-cloud-parametermanager/tests/unit/gapic/parametermanager_v1/test_parameter_manager.py +++ b/packages/google-cloud-parametermanager/tests/unit/gapic/parametermanager_v1/test_parameter_manager.py @@ -64,6 +64,13 @@ ) from google.cloud.parametermanager_v1.types import service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -323,6 +330,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ParameterManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ParameterManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -8269,10 +8319,13 @@ def test_list_parameters_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_list_parameters" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, "post_list_parameters_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_list_parameters" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListParametersRequest.pb(service.ListParametersRequest()) transcode.return_value = { "method": "post", @@ -8296,6 +8349,7 @@ def test_list_parameters_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListParametersResponse() + post_with_metadata.return_value = service.ListParametersResponse(), metadata client.list_parameters( request, @@ -8307,6 +8361,7 @@ def test_list_parameters_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_parameter_rest_bad_request(request_type=service.GetParameterRequest): @@ -8391,10 +8446,13 @@ def test_get_parameter_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_get_parameter" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, "post_get_parameter_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_get_parameter" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetParameterRequest.pb(service.GetParameterRequest()) transcode.return_value = { "method": "post", @@ -8416,6 +8474,7 @@ def test_get_parameter_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.Parameter() + post_with_metadata.return_value = service.Parameter(), metadata client.get_parameter( request, @@ -8427,6 +8486,7 @@ def test_get_parameter_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_parameter_rest_bad_request(request_type=service.CreateParameterRequest): @@ -8589,10 +8649,14 @@ def test_create_parameter_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_create_parameter" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_create_parameter_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_create_parameter" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateParameterRequest.pb(service.CreateParameterRequest()) transcode.return_value = { "method": "post", @@ -8614,6 +8678,7 @@ def test_create_parameter_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.Parameter() + post_with_metadata.return_value = service.Parameter(), metadata client.create_parameter( request, @@ -8625,6 +8690,7 @@ def test_create_parameter_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_parameter_rest_bad_request(request_type=service.UpdateParameterRequest): @@ -8791,10 +8857,14 @@ def test_update_parameter_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_update_parameter" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_update_parameter_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_update_parameter" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateParameterRequest.pb(service.UpdateParameterRequest()) transcode.return_value = { "method": "post", @@ -8816,6 +8886,7 @@ def test_update_parameter_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.Parameter() + post_with_metadata.return_value = service.Parameter(), metadata client.update_parameter( request, @@ -8827,6 +8898,7 @@ def test_update_parameter_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_parameter_rest_bad_request(request_type=service.DeleteParameterRequest): @@ -9018,10 +9090,14 @@ def test_list_parameter_versions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_list_parameter_versions" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_list_parameter_versions_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_list_parameter_versions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListParameterVersionsRequest.pb( service.ListParameterVersionsRequest() ) @@ -9047,6 +9123,10 @@ def test_list_parameter_versions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListParameterVersionsResponse() + post_with_metadata.return_value = ( + service.ListParameterVersionsResponse(), + metadata, + ) client.list_parameter_versions( request, @@ -9058,6 +9138,7 @@ def test_list_parameter_versions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_parameter_version_rest_bad_request( @@ -9148,10 +9229,14 @@ def test_get_parameter_version_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_get_parameter_version" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_get_parameter_version_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_get_parameter_version" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetParameterVersionRequest.pb( service.GetParameterVersionRequest() ) @@ -9175,6 +9260,7 @@ def test_get_parameter_version_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ParameterVersion() + post_with_metadata.return_value = service.ParameterVersion(), metadata client.get_parameter_version( request, @@ -9186,6 +9272,7 @@ def test_get_parameter_version_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_render_parameter_version_rest_bad_request( @@ -9276,10 +9363,14 @@ def test_render_parameter_version_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_render_parameter_version" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_render_parameter_version_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_render_parameter_version" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.RenderParameterVersionRequest.pb( service.RenderParameterVersionRequest() ) @@ -9305,6 +9396,10 @@ def test_render_parameter_version_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.RenderParameterVersionResponse() + post_with_metadata.return_value = ( + service.RenderParameterVersionResponse(), + metadata, + ) client.render_parameter_version( request, @@ -9316,6 +9411,7 @@ def test_render_parameter_version_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_parameter_version_rest_bad_request( @@ -9476,10 +9572,14 @@ def test_create_parameter_version_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_create_parameter_version" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_create_parameter_version_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_create_parameter_version" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateParameterVersionRequest.pb( service.CreateParameterVersionRequest() ) @@ -9503,6 +9603,7 @@ def test_create_parameter_version_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ParameterVersion() + post_with_metadata.return_value = service.ParameterVersion(), metadata client.create_parameter_version( request, @@ -9514,6 +9615,7 @@ def test_create_parameter_version_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_parameter_version_rest_bad_request( @@ -9682,10 +9784,14 @@ def test_update_parameter_version_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ParameterManagerRestInterceptor, "post_update_parameter_version" ) as post, mock.patch.object( + transports.ParameterManagerRestInterceptor, + "post_update_parameter_version_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ParameterManagerRestInterceptor, "pre_update_parameter_version" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateParameterVersionRequest.pb( service.UpdateParameterVersionRequest() ) @@ -9709,6 +9815,7 @@ def test_update_parameter_version_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ParameterVersion() + post_with_metadata.return_value = service.ParameterVersion(), metadata client.update_parameter_version( request, @@ -9720,6 +9827,7 @@ def test_update_parameter_version_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_parameter_version_rest_bad_request( diff --git a/packages/google-cloud-policy-troubleshooter/README.rst b/packages/google-cloud-policy-troubleshooter/README.rst index 5930501e4ad7..5766b03cf98a 100644 --- a/packages/google-cloud-policy-troubleshooter/README.rst +++ b/packages/google-cloud-policy-troubleshooter/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the IAM Policy Troubleshooter API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the IAM Policy Troubleshooter API.: https://cloud.google.com/iam/docs/troubleshooting-access#rest-api/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/client.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/client.py index 7b4813324e3a..b3e878ff84c3 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/client.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -465,6 +467,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/transports/rest.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/transports/rest.py index 90722d7080de..130195462595 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/transports/rest.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/services/iam_checker/transports/rest.py @@ -101,12 +101,37 @@ def post_troubleshoot_iam_policy( ) -> checker.TroubleshootIamPolicyResponse: """Post-rpc interceptor for troubleshoot_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_troubleshoot_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the IamChecker server but before - it is returned to user code. + it is returned to user code. This `post_troubleshoot_iam_policy` interceptor runs + before the `post_troubleshoot_iam_policy_with_metadata` interceptor. """ return response + def post_troubleshoot_iam_policy_with_metadata( + self, + response: checker.TroubleshootIamPolicyResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + checker.TroubleshootIamPolicyResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for troubleshoot_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the IamChecker server but before it is returned to user code. + + We recommend only using this `post_troubleshoot_iam_policy_with_metadata` + interceptor in new development instead of the `post_troubleshoot_iam_policy` interceptor. + When both interceptors are used, this `post_troubleshoot_iam_policy_with_metadata` interceptor runs after the + `post_troubleshoot_iam_policy` interceptor. The (possibly modified) response returned by + `post_troubleshoot_iam_policy` will be passed to + `post_troubleshoot_iam_policy_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class IamCheckerRestStub: @@ -325,6 +350,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_troubleshoot_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_troubleshoot_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-policy-troubleshooter/noxfile.py b/packages/google-cloud-policy-troubleshooter/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-policy-troubleshooter/noxfile.py +++ b/packages/google-cloud-policy-troubleshooter/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json b/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json index 71a44d1fca9d..24a7fb5b901c 100644 --- a/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json +++ b/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policy-troubleshooter", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-policy-troubleshooter/setup.py b/packages/google-cloud-policy-troubleshooter/setup.py index 3ababbab8ff8..d312bc69e44f 100644 --- a/packages/google-cloud-policy-troubleshooter/setup.py +++ b/packages/google-cloud-policy-troubleshooter/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-policy-troubleshooter" diff --git a/packages/google-cloud-policy-troubleshooter/testing/constraints-3.7.txt b/packages/google-cloud-policy-troubleshooter/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-policy-troubleshooter/testing/constraints-3.7.txt +++ b/packages/google-cloud-policy-troubleshooter/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-policy-troubleshooter/tests/unit/gapic/policytroubleshooter_v1/test_iam_checker.py b/packages/google-cloud-policy-troubleshooter/tests/unit/gapic/policytroubleshooter_v1/test_iam_checker.py index de24ce06f458..83ce4a17e9bf 100644 --- a/packages/google-cloud-policy-troubleshooter/tests/unit/gapic/policytroubleshooter_v1/test_iam_checker.py +++ b/packages/google-cloud-policy-troubleshooter/tests/unit/gapic/policytroubleshooter_v1/test_iam_checker.py @@ -60,6 +60,13 @@ ) from google.cloud.policytroubleshooter_v1.types import checker, explanations +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -295,6 +302,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = IamCheckerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = IamCheckerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1508,10 +1558,14 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.IamCheckerRestInterceptor, "post_troubleshoot_iam_policy" ) as post, mock.patch.object( + transports.IamCheckerRestInterceptor, + "post_troubleshoot_iam_policy_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.IamCheckerRestInterceptor, "pre_troubleshoot_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = checker.TroubleshootIamPolicyRequest.pb( checker.TroubleshootIamPolicyRequest() ) @@ -1537,6 +1591,10 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = checker.TroubleshootIamPolicyResponse() + post_with_metadata.return_value = ( + checker.TroubleshootIamPolicyResponse(), + metadata, + ) client.troubleshoot_iam_policy( request, @@ -1548,6 +1606,7 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-policysimulator/README.rst b/packages/google-cloud-policysimulator/README.rst index 35b8b7db54eb..9369f940f46d 100644 --- a/packages/google-cloud-policysimulator/README.rst +++ b/packages/google-cloud-policysimulator/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Policy Simulator API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Policy Simulator API.: https://cloud.google.com/policy-intelligence/docs/iam-simulator-overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py index 4b834789ba9e..558c8aab67c5 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.11" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py index 4b834789ba9e..558c8aab67c5 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.11" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/client.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/client.py index b0f78f897d30..b830304f041a 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/client.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -523,6 +525,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1152,16 +1181,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1207,16 +1240,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/transports/rest.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/transports/rest.py index a33fc9056af4..7bfd15ca2adb 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/transports/rest.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/services/simulator/transports/rest.py @@ -116,12 +116,35 @@ def post_create_replay( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_replay - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_replay_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Simulator server but before - it is returned to user code. + it is returned to user code. This `post_create_replay` interceptor runs + before the `post_create_replay_with_metadata` interceptor. """ return response + def post_create_replay_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_replay + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Simulator server but before it is returned to user code. + + We recommend only using this `post_create_replay_with_metadata` + interceptor in new development instead of the `post_create_replay` interceptor. + When both interceptors are used, this `post_create_replay_with_metadata` interceptor runs after the + `post_create_replay` interceptor. The (possibly modified) response returned by + `post_create_replay` will be passed to + `post_create_replay_with_metadata`. + """ + return response, metadata + def pre_get_replay( self, request: simulator.GetReplayRequest, @@ -137,12 +160,35 @@ def pre_get_replay( def post_get_replay(self, response: simulator.Replay) -> simulator.Replay: """Post-rpc interceptor for get_replay - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_replay_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Simulator server but before - it is returned to user code. + it is returned to user code. This `post_get_replay` interceptor runs + before the `post_get_replay_with_metadata` interceptor. """ return response + def post_get_replay_with_metadata( + self, + response: simulator.Replay, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[simulator.Replay, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_replay + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Simulator server but before it is returned to user code. + + We recommend only using this `post_get_replay_with_metadata` + interceptor in new development instead of the `post_get_replay` interceptor. + When both interceptors are used, this `post_get_replay_with_metadata` interceptor runs after the + `post_get_replay` interceptor. The (possibly modified) response returned by + `post_get_replay` will be passed to + `post_get_replay_with_metadata`. + """ + return response, metadata + def pre_list_replay_results( self, request: simulator.ListReplayResultsRequest, @@ -162,12 +208,37 @@ def post_list_replay_results( ) -> simulator.ListReplayResultsResponse: """Post-rpc interceptor for list_replay_results - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_replay_results_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Simulator server but before - it is returned to user code. + it is returned to user code. This `post_list_replay_results` interceptor runs + before the `post_list_replay_results_with_metadata` interceptor. """ return response + def post_list_replay_results_with_metadata( + self, + response: simulator.ListReplayResultsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + simulator.ListReplayResultsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_replay_results + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Simulator server but before it is returned to user code. + + We recommend only using this `post_list_replay_results_with_metadata` + interceptor in new development instead of the `post_list_replay_results` interceptor. + When both interceptors are used, this `post_list_replay_results_with_metadata` interceptor runs after the + `post_list_replay_results` interceptor. The (possibly modified) response returned by + `post_list_replay_results` will be passed to + `post_list_replay_results_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -511,6 +582,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_replay(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_replay_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -654,6 +729,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_replay(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_replay_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -799,6 +878,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_replay_results(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_replay_results_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-policysimulator/noxfile.py b/packages/google-cloud-policysimulator/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-policysimulator/noxfile.py +++ b/packages/google-cloud-policysimulator/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json b/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json index 5857fb9d6888..a6025abb1eff 100644 --- a/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json +++ b/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policysimulator", - "version": "0.1.11" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-policysimulator/setup.py b/packages/google-cloud-policysimulator/setup.py index 2310756692a7..41461d7cdee9 100644 --- a/packages/google-cloud-policysimulator/setup.py +++ b/packages/google-cloud-policysimulator/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-policysimulator" diff --git a/packages/google-cloud-policysimulator/testing/constraints-3.7.txt b/packages/google-cloud-policysimulator/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-policysimulator/testing/constraints-3.7.txt +++ b/packages/google-cloud-policysimulator/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-policysimulator/tests/unit/gapic/policysimulator_v1/test_simulator.py b/packages/google-cloud-policysimulator/tests/unit/gapic/policysimulator_v1/test_simulator.py index f480031f602e..6c38ef950569 100644 --- a/packages/google-cloud-policysimulator/tests/unit/gapic/policysimulator_v1/test_simulator.py +++ b/packages/google-cloud-policysimulator/tests/unit/gapic/policysimulator_v1/test_simulator.py @@ -73,6 +73,13 @@ ) from google.cloud.policysimulator_v1.types import simulator +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -306,6 +313,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = SimulatorClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = SimulatorClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3209,10 +3259,13 @@ def test_get_replay_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SimulatorRestInterceptor, "post_get_replay" ) as post, mock.patch.object( + transports.SimulatorRestInterceptor, "post_get_replay_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SimulatorRestInterceptor, "pre_get_replay" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = simulator.GetReplayRequest.pb(simulator.GetReplayRequest()) transcode.return_value = { "method": "post", @@ -3234,6 +3287,7 @@ def test_get_replay_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = simulator.Replay() + post_with_metadata.return_value = simulator.Replay(), metadata client.get_replay( request, @@ -3245,6 +3299,7 @@ def test_get_replay_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_replay_rest_bad_request(request_type=simulator.CreateReplayRequest): @@ -3401,10 +3456,13 @@ def test_create_replay_rest_interceptors(null_interceptor): ), mock.patch.object( transports.SimulatorRestInterceptor, "post_create_replay" ) as post, mock.patch.object( + transports.SimulatorRestInterceptor, "post_create_replay_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SimulatorRestInterceptor, "pre_create_replay" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = simulator.CreateReplayRequest.pb(simulator.CreateReplayRequest()) transcode.return_value = { "method": "post", @@ -3426,6 +3484,7 @@ def test_create_replay_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_replay( request, @@ -3437,6 +3496,7 @@ def test_create_replay_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_replay_results_rest_bad_request( @@ -3519,10 +3579,13 @@ def test_list_replay_results_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SimulatorRestInterceptor, "post_list_replay_results" ) as post, mock.patch.object( + transports.SimulatorRestInterceptor, "post_list_replay_results_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SimulatorRestInterceptor, "pre_list_replay_results" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = simulator.ListReplayResultsRequest.pb( simulator.ListReplayResultsRequest() ) @@ -3548,6 +3611,10 @@ def test_list_replay_results_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = simulator.ListReplayResultsResponse() + post_with_metadata.return_value = ( + simulator.ListReplayResultsResponse(), + metadata, + ) client.list_replay_results( request, @@ -3559,6 +3626,7 @@ def test_list_replay_results_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-policytroubleshooter-iam/README.rst b/packages/google-cloud-policytroubleshooter-iam/README.rst index cb8030c0a888..0101d3eb3abf 100644 --- a/packages/google-cloud-policytroubleshooter-iam/README.rst +++ b/packages/google-cloud-policytroubleshooter-iam/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Policy Troubleshooter API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Policy Troubleshooter API.: https://cloud.google.com/policy-intelligence/docs/troubleshoot-access -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py index 9413c3341313..558c8aab67c5 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py index 9413c3341313..558c8aab67c5 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/client.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/client.py index 0686abdd9876..7f7ca9470e99 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/client.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -465,6 +467,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/transports/rest.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/transports/rest.py index b86635758a38..3ed759ea84e9 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/transports/rest.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/services/policy_troubleshooter/transports/rest.py @@ -102,12 +102,38 @@ def post_troubleshoot_iam_policy( ) -> troubleshooter.TroubleshootIamPolicyResponse: """Post-rpc interceptor for troubleshoot_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_troubleshoot_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PolicyTroubleshooter server but before - it is returned to user code. + it is returned to user code. This `post_troubleshoot_iam_policy` interceptor runs + before the `post_troubleshoot_iam_policy_with_metadata` interceptor. """ return response + def post_troubleshoot_iam_policy_with_metadata( + self, + response: troubleshooter.TroubleshootIamPolicyResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + troubleshooter.TroubleshootIamPolicyResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for troubleshoot_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PolicyTroubleshooter server but before it is returned to user code. + + We recommend only using this `post_troubleshoot_iam_policy_with_metadata` + interceptor in new development instead of the `post_troubleshoot_iam_policy` interceptor. + When both interceptors are used, this `post_troubleshoot_iam_policy_with_metadata` interceptor runs after the + `post_troubleshoot_iam_policy` interceptor. The (possibly modified) response returned by + `post_troubleshoot_iam_policy` will be passed to + `post_troubleshoot_iam_policy_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PolicyTroubleshooterRestStub: @@ -329,6 +355,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_troubleshoot_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_troubleshoot_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-policytroubleshooter-iam/noxfile.py b/packages/google-cloud-policytroubleshooter-iam/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-policytroubleshooter-iam/noxfile.py +++ b/packages/google-cloud-policytroubleshooter-iam/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json b/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json index 4fd41c9fb941..3ec65c7e8d34 100644 --- a/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json +++ b/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policytroubleshooter-iam", - "version": "0.1.10" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-policytroubleshooter-iam/setup.py b/packages/google-cloud-policytroubleshooter-iam/setup.py index c6e561ca03a8..65ae4898ee85 100644 --- a/packages/google-cloud-policytroubleshooter-iam/setup.py +++ b/packages/google-cloud-policytroubleshooter-iam/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", "google-cloud-iam >= 2.12.2, <3.0.0dev", ] extras = {} diff --git a/packages/google-cloud-policytroubleshooter-iam/testing/constraints-3.7.txt b/packages/google-cloud-policytroubleshooter-iam/testing/constraints-3.7.txt index 351bc6a04ece..47b74ba1a8fa 100644 --- a/packages/google-cloud-policytroubleshooter-iam/testing/constraints-3.7.txt +++ b/packages/google-cloud-policytroubleshooter-iam/testing/constraints-3.7.txt @@ -8,5 +8,5 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 google-cloud-iam==2.12.2 diff --git a/packages/google-cloud-policytroubleshooter-iam/tests/unit/gapic/policytroubleshooter_iam_v3/test_policy_troubleshooter.py b/packages/google-cloud-policytroubleshooter-iam/tests/unit/gapic/policytroubleshooter_iam_v3/test_policy_troubleshooter.py index ba1ad796eeec..a12d94d22edd 100644 --- a/packages/google-cloud-policytroubleshooter-iam/tests/unit/gapic/policytroubleshooter_iam_v3/test_policy_troubleshooter.py +++ b/packages/google-cloud-policytroubleshooter-iam/tests/unit/gapic/policytroubleshooter_iam_v3/test_policy_troubleshooter.py @@ -60,6 +60,13 @@ ) from google.cloud.policytroubleshooter_iam_v3.types import troubleshooter +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -333,6 +340,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PolicyTroubleshooterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PolicyTroubleshooterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1619,10 +1669,14 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PolicyTroubleshooterRestInterceptor, "post_troubleshoot_iam_policy" ) as post, mock.patch.object( + transports.PolicyTroubleshooterRestInterceptor, + "post_troubleshoot_iam_policy_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PolicyTroubleshooterRestInterceptor, "pre_troubleshoot_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = troubleshooter.TroubleshootIamPolicyRequest.pb( troubleshooter.TroubleshootIamPolicyRequest() ) @@ -1648,6 +1702,10 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = troubleshooter.TroubleshootIamPolicyResponse() + post_with_metadata.return_value = ( + troubleshooter.TroubleshootIamPolicyResponse(), + metadata, + ) client.troubleshoot_iam_policy( request, @@ -1659,6 +1717,7 @@ def test_troubleshoot_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-private-ca/README.rst b/packages/google-cloud-private-ca/README.rst index 897a00e3f147..cdd98746dc3b 100644 --- a/packages/google-cloud-private-ca/README.rst +++ b/packages/google-cloud-private-ca/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Private Certificate Authority.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Private Certificate Authority.: https://cloud.google.com/certificate-authority-service -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/client.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/client.py index 606be23f4074..a27e9d5cec70 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/client.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -602,6 +604,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -4623,16 +4652,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -4678,16 +4711,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -4910,16 +4947,20 @@ def set_iam_policy( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_iam_policy( self, @@ -5032,16 +5073,20 @@ def get_iam_policy( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def test_iam_permissions( self, @@ -5092,16 +5137,20 @@ def test_iam_permissions( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_location( self, @@ -5147,16 +5196,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -5202,16 +5255,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/transports/rest.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/transports/rest.py index c317a66afd11..dc4c76d032eb 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/transports/rest.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/services/certificate_authority_service/transports/rest.py @@ -330,12 +330,35 @@ def post_activate_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for activate_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_activate_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_activate_certificate_authority` interceptor runs + before the `post_activate_certificate_authority_with_metadata` interceptor. """ return response + def post_activate_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for activate_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_activate_certificate_authority_with_metadata` + interceptor in new development instead of the `post_activate_certificate_authority` interceptor. + When both interceptors are used, this `post_activate_certificate_authority_with_metadata` interceptor runs after the + `post_activate_certificate_authority` interceptor. The (possibly modified) response returned by + `post_activate_certificate_authority` will be passed to + `post_activate_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_create_ca_pool( self, request: service.CreateCaPoolRequest, @@ -353,12 +376,35 @@ def post_create_ca_pool( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_ca_pool - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_ca_pool_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_ca_pool` interceptor runs + before the `post_create_ca_pool_with_metadata` interceptor. """ return response + def post_create_ca_pool_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_ca_pool + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_ca_pool_with_metadata` + interceptor in new development instead of the `post_create_ca_pool` interceptor. + When both interceptors are used, this `post_create_ca_pool_with_metadata` interceptor runs after the + `post_create_ca_pool` interceptor. The (possibly modified) response returned by + `post_create_ca_pool` will be passed to + `post_create_ca_pool_with_metadata`. + """ + return response, metadata + def pre_create_certificate( self, request: service.CreateCertificateRequest, @@ -378,12 +424,35 @@ def post_create_certificate( ) -> resources.Certificate: """Post-rpc interceptor for create_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_certificate` interceptor runs + before the `post_create_certificate_with_metadata` interceptor. """ return response + def post_create_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_certificate_with_metadata` + interceptor in new development instead of the `post_create_certificate` interceptor. + When both interceptors are used, this `post_create_certificate_with_metadata` interceptor runs after the + `post_create_certificate` interceptor. The (possibly modified) response returned by + `post_create_certificate` will be passed to + `post_create_certificate_with_metadata`. + """ + return response, metadata + def pre_create_certificate_authority( self, request: service.CreateCertificateAuthorityRequest, @@ -404,12 +473,35 @@ def post_create_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_certificate_authority` interceptor runs + before the `post_create_certificate_authority_with_metadata` interceptor. """ return response + def post_create_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_certificate_authority_with_metadata` + interceptor in new development instead of the `post_create_certificate_authority` interceptor. + When both interceptors are used, this `post_create_certificate_authority_with_metadata` interceptor runs after the + `post_create_certificate_authority` interceptor. The (possibly modified) response returned by + `post_create_certificate_authority` will be passed to + `post_create_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_create_certificate_template( self, request: service.CreateCertificateTemplateRequest, @@ -430,12 +522,35 @@ def post_create_certificate_template( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_certificate_template - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_certificate_template_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_certificate_template` interceptor runs + before the `post_create_certificate_template_with_metadata` interceptor. """ return response + def post_create_certificate_template_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_certificate_template + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_certificate_template_with_metadata` + interceptor in new development instead of the `post_create_certificate_template` interceptor. + When both interceptors are used, this `post_create_certificate_template_with_metadata` interceptor runs after the + `post_create_certificate_template` interceptor. The (possibly modified) response returned by + `post_create_certificate_template` will be passed to + `post_create_certificate_template_with_metadata`. + """ + return response, metadata + def pre_delete_ca_pool( self, request: service.DeleteCaPoolRequest, @@ -453,12 +568,35 @@ def post_delete_ca_pool( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_ca_pool - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_ca_pool_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_delete_ca_pool` interceptor runs + before the `post_delete_ca_pool_with_metadata` interceptor. """ return response + def post_delete_ca_pool_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_ca_pool + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_delete_ca_pool_with_metadata` + interceptor in new development instead of the `post_delete_ca_pool` interceptor. + When both interceptors are used, this `post_delete_ca_pool_with_metadata` interceptor runs after the + `post_delete_ca_pool` interceptor. The (possibly modified) response returned by + `post_delete_ca_pool` will be passed to + `post_delete_ca_pool_with_metadata`. + """ + return response, metadata + def pre_delete_certificate_authority( self, request: service.DeleteCertificateAuthorityRequest, @@ -479,12 +617,35 @@ def post_delete_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_delete_certificate_authority` interceptor runs + before the `post_delete_certificate_authority_with_metadata` interceptor. """ return response + def post_delete_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_delete_certificate_authority_with_metadata` + interceptor in new development instead of the `post_delete_certificate_authority` interceptor. + When both interceptors are used, this `post_delete_certificate_authority_with_metadata` interceptor runs after the + `post_delete_certificate_authority` interceptor. The (possibly modified) response returned by + `post_delete_certificate_authority` will be passed to + `post_delete_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_delete_certificate_template( self, request: service.DeleteCertificateTemplateRequest, @@ -505,12 +666,35 @@ def post_delete_certificate_template( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_certificate_template - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_certificate_template_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_delete_certificate_template` interceptor runs + before the `post_delete_certificate_template_with_metadata` interceptor. """ return response + def post_delete_certificate_template_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_certificate_template + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_delete_certificate_template_with_metadata` + interceptor in new development instead of the `post_delete_certificate_template` interceptor. + When both interceptors are used, this `post_delete_certificate_template_with_metadata` interceptor runs after the + `post_delete_certificate_template` interceptor. The (possibly modified) response returned by + `post_delete_certificate_template` will be passed to + `post_delete_certificate_template_with_metadata`. + """ + return response, metadata + def pre_disable_certificate_authority( self, request: service.DisableCertificateAuthorityRequest, @@ -531,12 +715,35 @@ def post_disable_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for disable_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_disable_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_disable_certificate_authority` interceptor runs + before the `post_disable_certificate_authority_with_metadata` interceptor. """ return response + def post_disable_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for disable_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_disable_certificate_authority_with_metadata` + interceptor in new development instead of the `post_disable_certificate_authority` interceptor. + When both interceptors are used, this `post_disable_certificate_authority_with_metadata` interceptor runs after the + `post_disable_certificate_authority` interceptor. The (possibly modified) response returned by + `post_disable_certificate_authority` will be passed to + `post_disable_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_enable_certificate_authority( self, request: service.EnableCertificateAuthorityRequest, @@ -557,12 +764,35 @@ def post_enable_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for enable_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_enable_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_enable_certificate_authority` interceptor runs + before the `post_enable_certificate_authority_with_metadata` interceptor. """ return response + def post_enable_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for enable_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_enable_certificate_authority_with_metadata` + interceptor in new development instead of the `post_enable_certificate_authority` interceptor. + When both interceptors are used, this `post_enable_certificate_authority_with_metadata` interceptor runs after the + `post_enable_certificate_authority` interceptor. The (possibly modified) response returned by + `post_enable_certificate_authority` will be passed to + `post_enable_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_fetch_ca_certs( self, request: service.FetchCaCertsRequest, @@ -580,12 +810,35 @@ def post_fetch_ca_certs( ) -> service.FetchCaCertsResponse: """Post-rpc interceptor for fetch_ca_certs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_fetch_ca_certs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_fetch_ca_certs` interceptor runs + before the `post_fetch_ca_certs_with_metadata` interceptor. """ return response + def post_fetch_ca_certs_with_metadata( + self, + response: service.FetchCaCertsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.FetchCaCertsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for fetch_ca_certs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_fetch_ca_certs_with_metadata` + interceptor in new development instead of the `post_fetch_ca_certs` interceptor. + When both interceptors are used, this `post_fetch_ca_certs_with_metadata` interceptor runs after the + `post_fetch_ca_certs` interceptor. The (possibly modified) response returned by + `post_fetch_ca_certs` will be passed to + `post_fetch_ca_certs_with_metadata`. + """ + return response, metadata + def pre_fetch_certificate_authority_csr( self, request: service.FetchCertificateAuthorityCsrRequest, @@ -606,12 +859,38 @@ def post_fetch_certificate_authority_csr( ) -> service.FetchCertificateAuthorityCsrResponse: """Post-rpc interceptor for fetch_certificate_authority_csr - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_fetch_certificate_authority_csr_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_fetch_certificate_authority_csr` interceptor runs + before the `post_fetch_certificate_authority_csr_with_metadata` interceptor. """ return response + def post_fetch_certificate_authority_csr_with_metadata( + self, + response: service.FetchCertificateAuthorityCsrResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.FetchCertificateAuthorityCsrResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for fetch_certificate_authority_csr + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_fetch_certificate_authority_csr_with_metadata` + interceptor in new development instead of the `post_fetch_certificate_authority_csr` interceptor. + When both interceptors are used, this `post_fetch_certificate_authority_csr_with_metadata` interceptor runs after the + `post_fetch_certificate_authority_csr` interceptor. The (possibly modified) response returned by + `post_fetch_certificate_authority_csr` will be passed to + `post_fetch_certificate_authority_csr_with_metadata`. + """ + return response, metadata + def pre_get_ca_pool( self, request: service.GetCaPoolRequest, @@ -627,12 +906,35 @@ def pre_get_ca_pool( def post_get_ca_pool(self, response: resources.CaPool) -> resources.CaPool: """Post-rpc interceptor for get_ca_pool - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_ca_pool_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_ca_pool` interceptor runs + before the `post_get_ca_pool_with_metadata` interceptor. """ return response + def post_get_ca_pool_with_metadata( + self, + response: resources.CaPool, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.CaPool, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_ca_pool + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_ca_pool_with_metadata` + interceptor in new development instead of the `post_get_ca_pool` interceptor. + When both interceptors are used, this `post_get_ca_pool_with_metadata` interceptor runs after the + `post_get_ca_pool` interceptor. The (possibly modified) response returned by + `post_get_ca_pool` will be passed to + `post_get_ca_pool_with_metadata`. + """ + return response, metadata + def pre_get_certificate( self, request: service.GetCertificateRequest, @@ -650,12 +952,35 @@ def post_get_certificate( ) -> resources.Certificate: """Post-rpc interceptor for get_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate` interceptor runs + before the `post_get_certificate_with_metadata` interceptor. """ return response + def post_get_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_with_metadata` + interceptor in new development instead of the `post_get_certificate` interceptor. + When both interceptors are used, this `post_get_certificate_with_metadata` interceptor runs after the + `post_get_certificate` interceptor. The (possibly modified) response returned by + `post_get_certificate` will be passed to + `post_get_certificate_with_metadata`. + """ + return response, metadata + def pre_get_certificate_authority( self, request: service.GetCertificateAuthorityRequest, @@ -675,12 +1000,35 @@ def post_get_certificate_authority( ) -> resources.CertificateAuthority: """Post-rpc interceptor for get_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate_authority` interceptor runs + before the `post_get_certificate_authority_with_metadata` interceptor. """ return response + def post_get_certificate_authority_with_metadata( + self, + response: resources.CertificateAuthority, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.CertificateAuthority, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_authority_with_metadata` + interceptor in new development instead of the `post_get_certificate_authority` interceptor. + When both interceptors are used, this `post_get_certificate_authority_with_metadata` interceptor runs after the + `post_get_certificate_authority` interceptor. The (possibly modified) response returned by + `post_get_certificate_authority` will be passed to + `post_get_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_get_certificate_revocation_list( self, request: service.GetCertificateRevocationListRequest, @@ -701,12 +1049,37 @@ def post_get_certificate_revocation_list( ) -> resources.CertificateRevocationList: """Post-rpc interceptor for get_certificate_revocation_list - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_revocation_list_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate_revocation_list` interceptor runs + before the `post_get_certificate_revocation_list_with_metadata` interceptor. """ return response + def post_get_certificate_revocation_list_with_metadata( + self, + response: resources.CertificateRevocationList, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + resources.CertificateRevocationList, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_certificate_revocation_list + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_revocation_list_with_metadata` + interceptor in new development instead of the `post_get_certificate_revocation_list` interceptor. + When both interceptors are used, this `post_get_certificate_revocation_list_with_metadata` interceptor runs after the + `post_get_certificate_revocation_list` interceptor. The (possibly modified) response returned by + `post_get_certificate_revocation_list` will be passed to + `post_get_certificate_revocation_list_with_metadata`. + """ + return response, metadata + def pre_get_certificate_template( self, request: service.GetCertificateTemplateRequest, @@ -726,12 +1099,35 @@ def post_get_certificate_template( ) -> resources.CertificateTemplate: """Post-rpc interceptor for get_certificate_template - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_template_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate_template` interceptor runs + before the `post_get_certificate_template_with_metadata` interceptor. """ return response + def post_get_certificate_template_with_metadata( + self, + response: resources.CertificateTemplate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.CertificateTemplate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_certificate_template + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_template_with_metadata` + interceptor in new development instead of the `post_get_certificate_template` interceptor. + When both interceptors are used, this `post_get_certificate_template_with_metadata` interceptor runs after the + `post_get_certificate_template` interceptor. The (possibly modified) response returned by + `post_get_certificate_template` will be passed to + `post_get_certificate_template_with_metadata`. + """ + return response, metadata + def pre_list_ca_pools( self, request: service.ListCaPoolsRequest, @@ -749,12 +1145,35 @@ def post_list_ca_pools( ) -> service.ListCaPoolsResponse: """Post-rpc interceptor for list_ca_pools - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_ca_pools_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_ca_pools` interceptor runs + before the `post_list_ca_pools_with_metadata` interceptor. """ return response + def post_list_ca_pools_with_metadata( + self, + response: service.ListCaPoolsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[service.ListCaPoolsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_ca_pools + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_ca_pools_with_metadata` + interceptor in new development instead of the `post_list_ca_pools` interceptor. + When both interceptors are used, this `post_list_ca_pools_with_metadata` interceptor runs after the + `post_list_ca_pools` interceptor. The (possibly modified) response returned by + `post_list_ca_pools` will be passed to + `post_list_ca_pools_with_metadata`. + """ + return response, metadata + def pre_list_certificate_authorities( self, request: service.ListCertificateAuthoritiesRequest, @@ -775,12 +1194,38 @@ def post_list_certificate_authorities( ) -> service.ListCertificateAuthoritiesResponse: """Post-rpc interceptor for list_certificate_authorities - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificate_authorities_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificate_authorities` interceptor runs + before the `post_list_certificate_authorities_with_metadata` interceptor. """ return response + def post_list_certificate_authorities_with_metadata( + self, + response: service.ListCertificateAuthoritiesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificateAuthoritiesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_certificate_authorities + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificate_authorities_with_metadata` + interceptor in new development instead of the `post_list_certificate_authorities` interceptor. + When both interceptors are used, this `post_list_certificate_authorities_with_metadata` interceptor runs after the + `post_list_certificate_authorities` interceptor. The (possibly modified) response returned by + `post_list_certificate_authorities` will be passed to + `post_list_certificate_authorities_with_metadata`. + """ + return response, metadata + def pre_list_certificate_revocation_lists( self, request: service.ListCertificateRevocationListsRequest, @@ -801,12 +1246,38 @@ def post_list_certificate_revocation_lists( ) -> service.ListCertificateRevocationListsResponse: """Post-rpc interceptor for list_certificate_revocation_lists - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificate_revocation_lists_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificate_revocation_lists` interceptor runs + before the `post_list_certificate_revocation_lists_with_metadata` interceptor. """ return response + def post_list_certificate_revocation_lists_with_metadata( + self, + response: service.ListCertificateRevocationListsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificateRevocationListsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_certificate_revocation_lists + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificate_revocation_lists_with_metadata` + interceptor in new development instead of the `post_list_certificate_revocation_lists` interceptor. + When both interceptors are used, this `post_list_certificate_revocation_lists_with_metadata` interceptor runs after the + `post_list_certificate_revocation_lists` interceptor. The (possibly modified) response returned by + `post_list_certificate_revocation_lists` will be passed to + `post_list_certificate_revocation_lists_with_metadata`. + """ + return response, metadata + def pre_list_certificates( self, request: service.ListCertificatesRequest, @@ -826,12 +1297,37 @@ def post_list_certificates( ) -> service.ListCertificatesResponse: """Post-rpc interceptor for list_certificates - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificates_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificates` interceptor runs + before the `post_list_certificates_with_metadata` interceptor. """ return response + def post_list_certificates_with_metadata( + self, + response: service.ListCertificatesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificatesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_certificates + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificates_with_metadata` + interceptor in new development instead of the `post_list_certificates` interceptor. + When both interceptors are used, this `post_list_certificates_with_metadata` interceptor runs after the + `post_list_certificates` interceptor. The (possibly modified) response returned by + `post_list_certificates` will be passed to + `post_list_certificates_with_metadata`. + """ + return response, metadata + def pre_list_certificate_templates( self, request: service.ListCertificateTemplatesRequest, @@ -851,12 +1347,38 @@ def post_list_certificate_templates( ) -> service.ListCertificateTemplatesResponse: """Post-rpc interceptor for list_certificate_templates - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificate_templates_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificate_templates` interceptor runs + before the `post_list_certificate_templates_with_metadata` interceptor. """ return response + def post_list_certificate_templates_with_metadata( + self, + response: service.ListCertificateTemplatesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificateTemplatesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_certificate_templates + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificate_templates_with_metadata` + interceptor in new development instead of the `post_list_certificate_templates` interceptor. + When both interceptors are used, this `post_list_certificate_templates_with_metadata` interceptor runs after the + `post_list_certificate_templates` interceptor. The (possibly modified) response returned by + `post_list_certificate_templates` will be passed to + `post_list_certificate_templates_with_metadata`. + """ + return response, metadata + def pre_revoke_certificate( self, request: service.RevokeCertificateRequest, @@ -876,12 +1398,35 @@ def post_revoke_certificate( ) -> resources.Certificate: """Post-rpc interceptor for revoke_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_revoke_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_revoke_certificate` interceptor runs + before the `post_revoke_certificate_with_metadata` interceptor. """ return response + def post_revoke_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for revoke_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_revoke_certificate_with_metadata` + interceptor in new development instead of the `post_revoke_certificate` interceptor. + When both interceptors are used, this `post_revoke_certificate_with_metadata` interceptor runs after the + `post_revoke_certificate` interceptor. The (possibly modified) response returned by + `post_revoke_certificate` will be passed to + `post_revoke_certificate_with_metadata`. + """ + return response, metadata + def pre_undelete_certificate_authority( self, request: service.UndeleteCertificateAuthorityRequest, @@ -902,12 +1447,35 @@ def post_undelete_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for undelete_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_undelete_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_undelete_certificate_authority` interceptor runs + before the `post_undelete_certificate_authority_with_metadata` interceptor. """ return response + def post_undelete_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for undelete_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_undelete_certificate_authority_with_metadata` + interceptor in new development instead of the `post_undelete_certificate_authority` interceptor. + When both interceptors are used, this `post_undelete_certificate_authority_with_metadata` interceptor runs after the + `post_undelete_certificate_authority` interceptor. The (possibly modified) response returned by + `post_undelete_certificate_authority` will be passed to + `post_undelete_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_update_ca_pool( self, request: service.UpdateCaPoolRequest, @@ -925,12 +1493,35 @@ def post_update_ca_pool( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_ca_pool - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_ca_pool_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_ca_pool` interceptor runs + before the `post_update_ca_pool_with_metadata` interceptor. """ return response + def post_update_ca_pool_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_ca_pool + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_ca_pool_with_metadata` + interceptor in new development instead of the `post_update_ca_pool` interceptor. + When both interceptors are used, this `post_update_ca_pool_with_metadata` interceptor runs after the + `post_update_ca_pool` interceptor. The (possibly modified) response returned by + `post_update_ca_pool` will be passed to + `post_update_ca_pool_with_metadata`. + """ + return response, metadata + def pre_update_certificate( self, request: service.UpdateCertificateRequest, @@ -950,12 +1541,35 @@ def post_update_certificate( ) -> resources.Certificate: """Post-rpc interceptor for update_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate` interceptor runs + before the `post_update_certificate_with_metadata` interceptor. """ return response + def post_update_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_with_metadata` + interceptor in new development instead of the `post_update_certificate` interceptor. + When both interceptors are used, this `post_update_certificate_with_metadata` interceptor runs after the + `post_update_certificate` interceptor. The (possibly modified) response returned by + `post_update_certificate` will be passed to + `post_update_certificate_with_metadata`. + """ + return response, metadata + def pre_update_certificate_authority( self, request: service.UpdateCertificateAuthorityRequest, @@ -976,12 +1590,35 @@ def post_update_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate_authority` interceptor runs + before the `post_update_certificate_authority_with_metadata` interceptor. """ return response + def post_update_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_authority_with_metadata` + interceptor in new development instead of the `post_update_certificate_authority` interceptor. + When both interceptors are used, this `post_update_certificate_authority_with_metadata` interceptor runs after the + `post_update_certificate_authority` interceptor. The (possibly modified) response returned by + `post_update_certificate_authority` will be passed to + `post_update_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_update_certificate_revocation_list( self, request: service.UpdateCertificateRevocationListRequest, @@ -1002,12 +1639,35 @@ def post_update_certificate_revocation_list( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_certificate_revocation_list - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_revocation_list_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate_revocation_list` interceptor runs + before the `post_update_certificate_revocation_list_with_metadata` interceptor. """ return response + def post_update_certificate_revocation_list_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate_revocation_list + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_revocation_list_with_metadata` + interceptor in new development instead of the `post_update_certificate_revocation_list` interceptor. + When both interceptors are used, this `post_update_certificate_revocation_list_with_metadata` interceptor runs after the + `post_update_certificate_revocation_list` interceptor. The (possibly modified) response returned by + `post_update_certificate_revocation_list` will be passed to + `post_update_certificate_revocation_list_with_metadata`. + """ + return response, metadata + def pre_update_certificate_template( self, request: service.UpdateCertificateTemplateRequest, @@ -1028,12 +1688,35 @@ def post_update_certificate_template( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_certificate_template - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_template_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate_template` interceptor runs + before the `post_update_certificate_template_with_metadata` interceptor. """ return response + def post_update_certificate_template_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate_template + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_template_with_metadata` + interceptor in new development instead of the `post_update_certificate_template` interceptor. + When both interceptors are used, this `post_update_certificate_template_with_metadata` interceptor runs after the + `post_update_certificate_template` interceptor. The (possibly modified) response returned by + `post_update_certificate_template` will be passed to + `post_update_certificate_template_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -1528,6 +2211,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_activate_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_activate_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1679,6 +2369,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_ca_pool(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_ca_pool_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1833,6 +2527,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1987,6 +2685,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2141,6 +2843,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_certificate_template(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_certificate_template_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2286,6 +2992,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_ca_pool(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_ca_pool_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2434,6 +3144,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2582,6 +3296,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_certificate_template(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_certificate_template_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2736,6 +3454,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_disable_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_disable_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2890,6 +3615,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_enable_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_enable_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3042,6 +3771,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_fetch_ca_certs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_fetch_ca_certs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3191,6 +3924,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_fetch_certificate_authority_csr(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_fetch_certificate_authority_csr_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3346,6 +4086,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_ca_pool(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_ca_pool_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3494,6 +4238,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3646,6 +4394,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3798,6 +4550,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate_revocation_list(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_certificate_revocation_list_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3949,6 +4708,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate_template(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_certificate_template_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4095,6 +4858,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_ca_pools(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_ca_pools_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4244,6 +5011,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificate_authorities(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_certificate_authorities_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4395,6 +5166,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificate_revocation_lists(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_certificate_revocation_lists_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4543,6 +5321,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificates(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_certificates_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4694,6 +5476,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificate_templates(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_certificate_templates_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -4850,6 +5636,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_revoke_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_revoke_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5004,6 +5794,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_undelete_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_undelete_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5155,6 +5952,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_ca_pool(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_ca_pool_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5309,6 +6110,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5463,6 +6268,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5620,6 +6429,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate_revocation_list(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_certificate_revocation_list_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -5774,6 +6590,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate_template(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_certificate_template_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/client.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/client.py index 51f06dda205b..a3655a2d4adb 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/client.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -571,6 +573,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/transports/rest.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/transports/rest.py index 3c171c10269a..77cdeafccdf0 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/transports/rest.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/services/certificate_authority_service/transports/rest.py @@ -255,12 +255,35 @@ def post_activate_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for activate_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_activate_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_activate_certificate_authority` interceptor runs + before the `post_activate_certificate_authority_with_metadata` interceptor. """ return response + def post_activate_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for activate_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_activate_certificate_authority_with_metadata` + interceptor in new development instead of the `post_activate_certificate_authority` interceptor. + When both interceptors are used, this `post_activate_certificate_authority_with_metadata` interceptor runs after the + `post_activate_certificate_authority` interceptor. The (possibly modified) response returned by + `post_activate_certificate_authority` will be passed to + `post_activate_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_create_certificate( self, request: service.CreateCertificateRequest, @@ -280,12 +303,35 @@ def post_create_certificate( ) -> resources.Certificate: """Post-rpc interceptor for create_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_certificate` interceptor runs + before the `post_create_certificate_with_metadata` interceptor. """ return response + def post_create_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_certificate_with_metadata` + interceptor in new development instead of the `post_create_certificate` interceptor. + When both interceptors are used, this `post_create_certificate_with_metadata` interceptor runs after the + `post_create_certificate` interceptor. The (possibly modified) response returned by + `post_create_certificate` will be passed to + `post_create_certificate_with_metadata`. + """ + return response, metadata + def pre_create_certificate_authority( self, request: service.CreateCertificateAuthorityRequest, @@ -306,12 +352,35 @@ def post_create_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_certificate_authority` interceptor runs + before the `post_create_certificate_authority_with_metadata` interceptor. """ return response + def post_create_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_certificate_authority_with_metadata` + interceptor in new development instead of the `post_create_certificate_authority` interceptor. + When both interceptors are used, this `post_create_certificate_authority_with_metadata` interceptor runs after the + `post_create_certificate_authority` interceptor. The (possibly modified) response returned by + `post_create_certificate_authority` will be passed to + `post_create_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_disable_certificate_authority( self, request: service.DisableCertificateAuthorityRequest, @@ -332,12 +401,35 @@ def post_disable_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for disable_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_disable_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_disable_certificate_authority` interceptor runs + before the `post_disable_certificate_authority_with_metadata` interceptor. """ return response + def post_disable_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for disable_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_disable_certificate_authority_with_metadata` + interceptor in new development instead of the `post_disable_certificate_authority` interceptor. + When both interceptors are used, this `post_disable_certificate_authority_with_metadata` interceptor runs after the + `post_disable_certificate_authority` interceptor. The (possibly modified) response returned by + `post_disable_certificate_authority` will be passed to + `post_disable_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_enable_certificate_authority( self, request: service.EnableCertificateAuthorityRequest, @@ -358,12 +450,35 @@ def post_enable_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for enable_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_enable_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_enable_certificate_authority` interceptor runs + before the `post_enable_certificate_authority_with_metadata` interceptor. """ return response + def post_enable_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for enable_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_enable_certificate_authority_with_metadata` + interceptor in new development instead of the `post_enable_certificate_authority` interceptor. + When both interceptors are used, this `post_enable_certificate_authority_with_metadata` interceptor runs after the + `post_enable_certificate_authority` interceptor. The (possibly modified) response returned by + `post_enable_certificate_authority` will be passed to + `post_enable_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_fetch_certificate_authority_csr( self, request: service.FetchCertificateAuthorityCsrRequest, @@ -384,12 +499,38 @@ def post_fetch_certificate_authority_csr( ) -> service.FetchCertificateAuthorityCsrResponse: """Post-rpc interceptor for fetch_certificate_authority_csr - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_fetch_certificate_authority_csr_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_fetch_certificate_authority_csr` interceptor runs + before the `post_fetch_certificate_authority_csr_with_metadata` interceptor. """ return response + def post_fetch_certificate_authority_csr_with_metadata( + self, + response: service.FetchCertificateAuthorityCsrResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.FetchCertificateAuthorityCsrResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for fetch_certificate_authority_csr + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_fetch_certificate_authority_csr_with_metadata` + interceptor in new development instead of the `post_fetch_certificate_authority_csr` interceptor. + When both interceptors are used, this `post_fetch_certificate_authority_csr_with_metadata` interceptor runs after the + `post_fetch_certificate_authority_csr` interceptor. The (possibly modified) response returned by + `post_fetch_certificate_authority_csr` will be passed to + `post_fetch_certificate_authority_csr_with_metadata`. + """ + return response, metadata + def pre_get_certificate( self, request: service.GetCertificateRequest, @@ -407,12 +548,35 @@ def post_get_certificate( ) -> resources.Certificate: """Post-rpc interceptor for get_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate` interceptor runs + before the `post_get_certificate_with_metadata` interceptor. """ return response + def post_get_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_with_metadata` + interceptor in new development instead of the `post_get_certificate` interceptor. + When both interceptors are used, this `post_get_certificate_with_metadata` interceptor runs after the + `post_get_certificate` interceptor. The (possibly modified) response returned by + `post_get_certificate` will be passed to + `post_get_certificate_with_metadata`. + """ + return response, metadata + def pre_get_certificate_authority( self, request: service.GetCertificateAuthorityRequest, @@ -432,12 +596,35 @@ def post_get_certificate_authority( ) -> resources.CertificateAuthority: """Post-rpc interceptor for get_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate_authority` interceptor runs + before the `post_get_certificate_authority_with_metadata` interceptor. """ return response + def post_get_certificate_authority_with_metadata( + self, + response: resources.CertificateAuthority, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.CertificateAuthority, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_authority_with_metadata` + interceptor in new development instead of the `post_get_certificate_authority` interceptor. + When both interceptors are used, this `post_get_certificate_authority_with_metadata` interceptor runs after the + `post_get_certificate_authority` interceptor. The (possibly modified) response returned by + `post_get_certificate_authority` will be passed to + `post_get_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_get_certificate_revocation_list( self, request: service.GetCertificateRevocationListRequest, @@ -458,12 +645,37 @@ def post_get_certificate_revocation_list( ) -> resources.CertificateRevocationList: """Post-rpc interceptor for get_certificate_revocation_list - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_certificate_revocation_list_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_certificate_revocation_list` interceptor runs + before the `post_get_certificate_revocation_list_with_metadata` interceptor. """ return response + def post_get_certificate_revocation_list_with_metadata( + self, + response: resources.CertificateRevocationList, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + resources.CertificateRevocationList, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_certificate_revocation_list + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_certificate_revocation_list_with_metadata` + interceptor in new development instead of the `post_get_certificate_revocation_list` interceptor. + When both interceptors are used, this `post_get_certificate_revocation_list_with_metadata` interceptor runs after the + `post_get_certificate_revocation_list` interceptor. The (possibly modified) response returned by + `post_get_certificate_revocation_list` will be passed to + `post_get_certificate_revocation_list_with_metadata`. + """ + return response, metadata + def pre_get_reusable_config( self, request: service.GetReusableConfigRequest, @@ -483,12 +695,35 @@ def post_get_reusable_config( ) -> resources.ReusableConfig: """Post-rpc interceptor for get_reusable_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_reusable_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_get_reusable_config` interceptor runs + before the `post_get_reusable_config_with_metadata` interceptor. """ return response + def post_get_reusable_config_with_metadata( + self, + response: resources.ReusableConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.ReusableConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_reusable_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_get_reusable_config_with_metadata` + interceptor in new development instead of the `post_get_reusable_config` interceptor. + When both interceptors are used, this `post_get_reusable_config_with_metadata` interceptor runs after the + `post_get_reusable_config` interceptor. The (possibly modified) response returned by + `post_get_reusable_config` will be passed to + `post_get_reusable_config_with_metadata`. + """ + return response, metadata + def pre_list_certificate_authorities( self, request: service.ListCertificateAuthoritiesRequest, @@ -509,12 +744,38 @@ def post_list_certificate_authorities( ) -> service.ListCertificateAuthoritiesResponse: """Post-rpc interceptor for list_certificate_authorities - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificate_authorities_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificate_authorities` interceptor runs + before the `post_list_certificate_authorities_with_metadata` interceptor. """ return response + def post_list_certificate_authorities_with_metadata( + self, + response: service.ListCertificateAuthoritiesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificateAuthoritiesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_certificate_authorities + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificate_authorities_with_metadata` + interceptor in new development instead of the `post_list_certificate_authorities` interceptor. + When both interceptors are used, this `post_list_certificate_authorities_with_metadata` interceptor runs after the + `post_list_certificate_authorities` interceptor. The (possibly modified) response returned by + `post_list_certificate_authorities` will be passed to + `post_list_certificate_authorities_with_metadata`. + """ + return response, metadata + def pre_list_certificate_revocation_lists( self, request: service.ListCertificateRevocationListsRequest, @@ -535,12 +796,38 @@ def post_list_certificate_revocation_lists( ) -> service.ListCertificateRevocationListsResponse: """Post-rpc interceptor for list_certificate_revocation_lists - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificate_revocation_lists_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificate_revocation_lists` interceptor runs + before the `post_list_certificate_revocation_lists_with_metadata` interceptor. """ return response + def post_list_certificate_revocation_lists_with_metadata( + self, + response: service.ListCertificateRevocationListsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificateRevocationListsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_certificate_revocation_lists + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificate_revocation_lists_with_metadata` + interceptor in new development instead of the `post_list_certificate_revocation_lists` interceptor. + When both interceptors are used, this `post_list_certificate_revocation_lists_with_metadata` interceptor runs after the + `post_list_certificate_revocation_lists` interceptor. The (possibly modified) response returned by + `post_list_certificate_revocation_lists` will be passed to + `post_list_certificate_revocation_lists_with_metadata`. + """ + return response, metadata + def pre_list_certificates( self, request: service.ListCertificatesRequest, @@ -560,12 +847,37 @@ def post_list_certificates( ) -> service.ListCertificatesResponse: """Post-rpc interceptor for list_certificates - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_certificates_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_certificates` interceptor runs + before the `post_list_certificates_with_metadata` interceptor. """ return response + def post_list_certificates_with_metadata( + self, + response: service.ListCertificatesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListCertificatesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_certificates + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_certificates_with_metadata` + interceptor in new development instead of the `post_list_certificates` interceptor. + When both interceptors are used, this `post_list_certificates_with_metadata` interceptor runs after the + `post_list_certificates` interceptor. The (possibly modified) response returned by + `post_list_certificates` will be passed to + `post_list_certificates_with_metadata`. + """ + return response, metadata + def pre_list_reusable_configs( self, request: service.ListReusableConfigsRequest, @@ -585,12 +897,37 @@ def post_list_reusable_configs( ) -> service.ListReusableConfigsResponse: """Post-rpc interceptor for list_reusable_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_reusable_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_list_reusable_configs` interceptor runs + before the `post_list_reusable_configs_with_metadata` interceptor. """ return response + def post_list_reusable_configs_with_metadata( + self, + response: service.ListReusableConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + service.ListReusableConfigsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_reusable_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_list_reusable_configs_with_metadata` + interceptor in new development instead of the `post_list_reusable_configs` interceptor. + When both interceptors are used, this `post_list_reusable_configs_with_metadata` interceptor runs after the + `post_list_reusable_configs` interceptor. The (possibly modified) response returned by + `post_list_reusable_configs` will be passed to + `post_list_reusable_configs_with_metadata`. + """ + return response, metadata + def pre_restore_certificate_authority( self, request: service.RestoreCertificateAuthorityRequest, @@ -611,12 +948,35 @@ def post_restore_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for restore_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_restore_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_restore_certificate_authority` interceptor runs + before the `post_restore_certificate_authority_with_metadata` interceptor. """ return response + def post_restore_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for restore_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_restore_certificate_authority_with_metadata` + interceptor in new development instead of the `post_restore_certificate_authority` interceptor. + When both interceptors are used, this `post_restore_certificate_authority_with_metadata` interceptor runs after the + `post_restore_certificate_authority` interceptor. The (possibly modified) response returned by + `post_restore_certificate_authority` will be passed to + `post_restore_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_revoke_certificate( self, request: service.RevokeCertificateRequest, @@ -636,12 +996,35 @@ def post_revoke_certificate( ) -> resources.Certificate: """Post-rpc interceptor for revoke_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_revoke_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_revoke_certificate` interceptor runs + before the `post_revoke_certificate_with_metadata` interceptor. """ return response + def post_revoke_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for revoke_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_revoke_certificate_with_metadata` + interceptor in new development instead of the `post_revoke_certificate` interceptor. + When both interceptors are used, this `post_revoke_certificate_with_metadata` interceptor runs after the + `post_revoke_certificate` interceptor. The (possibly modified) response returned by + `post_revoke_certificate` will be passed to + `post_revoke_certificate_with_metadata`. + """ + return response, metadata + def pre_schedule_delete_certificate_authority( self, request: service.ScheduleDeleteCertificateAuthorityRequest, @@ -662,12 +1045,35 @@ def post_schedule_delete_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for schedule_delete_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_schedule_delete_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_schedule_delete_certificate_authority` interceptor runs + before the `post_schedule_delete_certificate_authority_with_metadata` interceptor. """ return response + def post_schedule_delete_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for schedule_delete_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_schedule_delete_certificate_authority_with_metadata` + interceptor in new development instead of the `post_schedule_delete_certificate_authority` interceptor. + When both interceptors are used, this `post_schedule_delete_certificate_authority_with_metadata` interceptor runs after the + `post_schedule_delete_certificate_authority` interceptor. The (possibly modified) response returned by + `post_schedule_delete_certificate_authority` will be passed to + `post_schedule_delete_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_update_certificate( self, request: service.UpdateCertificateRequest, @@ -687,12 +1093,35 @@ def post_update_certificate( ) -> resources.Certificate: """Post-rpc interceptor for update_certificate - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate` interceptor runs + before the `post_update_certificate_with_metadata` interceptor. """ return response + def post_update_certificate_with_metadata( + self, + response: resources.Certificate, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.Certificate, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_with_metadata` + interceptor in new development instead of the `post_update_certificate` interceptor. + When both interceptors are used, this `post_update_certificate_with_metadata` interceptor runs after the + `post_update_certificate` interceptor. The (possibly modified) response returned by + `post_update_certificate` will be passed to + `post_update_certificate_with_metadata`. + """ + return response, metadata + def pre_update_certificate_authority( self, request: service.UpdateCertificateAuthorityRequest, @@ -713,12 +1142,35 @@ def post_update_certificate_authority( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate_authority` interceptor runs + before the `post_update_certificate_authority_with_metadata` interceptor. """ return response + def post_update_certificate_authority_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_authority_with_metadata` + interceptor in new development instead of the `post_update_certificate_authority` interceptor. + When both interceptors are used, this `post_update_certificate_authority_with_metadata` interceptor runs after the + `post_update_certificate_authority` interceptor. The (possibly modified) response returned by + `post_update_certificate_authority` will be passed to + `post_update_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_update_certificate_revocation_list( self, request: service.UpdateCertificateRevocationListRequest, @@ -739,12 +1191,35 @@ def post_update_certificate_revocation_list( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_certificate_revocation_list - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_certificate_revocation_list_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_update_certificate_revocation_list` interceptor runs + before the `post_update_certificate_revocation_list_with_metadata` interceptor. """ return response + def post_update_certificate_revocation_list_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_certificate_revocation_list + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_update_certificate_revocation_list_with_metadata` + interceptor in new development instead of the `post_update_certificate_revocation_list` interceptor. + When both interceptors are used, this `post_update_certificate_revocation_list_with_metadata` interceptor runs after the + `post_update_certificate_revocation_list` interceptor. The (possibly modified) response returned by + `post_update_certificate_revocation_list` will be passed to + `post_update_certificate_revocation_list_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CertificateAuthorityServiceRestStub: @@ -1021,6 +1496,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_activate_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_activate_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1175,6 +1657,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1329,6 +1815,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1483,6 +1973,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_disable_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_disable_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1637,6 +2134,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_enable_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_enable_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1786,6 +2287,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_fetch_certificate_authority_csr(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_fetch_certificate_authority_csr_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1936,6 +2444,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2088,6 +2600,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2240,6 +2756,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_certificate_revocation_list(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_certificate_revocation_list_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2394,6 +2917,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_reusable_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_reusable_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2543,6 +3070,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificate_authorities(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_certificate_authorities_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2694,6 +3225,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificate_revocation_lists(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_certificate_revocation_lists_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2842,6 +3380,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_certificates(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_certificates_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2990,6 +3532,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_reusable_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_reusable_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3146,6 +3692,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_restore_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_restore_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3300,6 +3853,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_revoke_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_revoke_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3457,6 +4014,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_schedule_delete_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_schedule_delete_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3611,6 +4175,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_certificate_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3765,6 +4333,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -3922,6 +4494,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_certificate_revocation_list(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_certificate_revocation_list_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-private-ca/noxfile.py b/packages/google-cloud-private-ca/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-private-ca/noxfile.py +++ b/packages/google-cloud-private-ca/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json index aac0f3c6ce6c..ca2ab4a8547d 100644 --- a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json +++ b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-ca", - "version": "1.14.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json index 96948e797a89..a2c343c16a72 100644 --- a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json +++ b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-ca", - "version": "1.14.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-private-ca/setup.py b/packages/google-cloud-private-ca/setup.py index ad9c59b492ad..18bc6586b4b6 100644 --- a/packages/google-cloud-private-ca/setup.py +++ b/packages/google-cloud-private-ca/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-private-ca" diff --git a/packages/google-cloud-private-ca/testing/constraints-3.7.txt b/packages/google-cloud-private-ca/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-private-ca/testing/constraints-3.7.txt +++ b/packages/google-cloud-private-ca/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1/test_certificate_authority_service.py b/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1/test_certificate_authority_service.py index d0c66d880a29..cac20a925e81 100644 --- a/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1/test_certificate_authority_service.py +++ b/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1/test_certificate_authority_service.py @@ -79,6 +79,13 @@ ) from google.cloud.security.privateca_v1.types import resources, service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -362,6 +369,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -20315,10 +20365,14 @@ def test_create_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_create_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCertificateRequest.pb( service.CreateCertificateRequest() ) @@ -20342,6 +20396,7 @@ def test_create_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.create_certificate( request, @@ -20353,6 +20408,7 @@ def test_create_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_rest_bad_request(request_type=service.GetCertificateRequest): @@ -20450,10 +20506,14 @@ def test_get_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateRequest.pb(service.GetCertificateRequest()) transcode.return_value = { "method": "post", @@ -20475,6 +20535,7 @@ def test_get_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.get_certificate( request, @@ -20486,6 +20547,7 @@ def test_get_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificates_rest_bad_request( @@ -20572,10 +20634,14 @@ def test_list_certificates_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificates" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificates_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificates" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificatesRequest.pb( service.ListCertificatesRequest() ) @@ -20601,6 +20667,7 @@ def test_list_certificates_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificatesResponse() + post_with_metadata.return_value = service.ListCertificatesResponse(), metadata client.list_certificates( request, @@ -20612,6 +20679,7 @@ def test_list_certificates_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_revoke_certificate_rest_bad_request( @@ -20711,10 +20779,14 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_revoke_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_revoke_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_revoke_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.RevokeCertificateRequest.pb( service.RevokeCertificateRequest() ) @@ -20738,6 +20810,7 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.revoke_certificate( request, @@ -20749,6 +20822,7 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_rest_bad_request( @@ -21057,10 +21131,14 @@ def test_update_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateRequest.pb( service.UpdateCertificateRequest() ) @@ -21084,6 +21162,7 @@ def test_update_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.update_certificate( request, @@ -21095,6 +21174,7 @@ def test_update_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_activate_certificate_authority_rest_bad_request( @@ -21180,11 +21260,15 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_activate_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_activate_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_activate_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ActivateCertificateAuthorityRequest.pb( service.ActivateCertificateAuthorityRequest() ) @@ -21208,6 +21292,7 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.activate_certificate_authority( request, @@ -21219,6 +21304,7 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_certificate_authority_rest_bad_request( @@ -21525,11 +21611,15 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_create_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCertificateAuthorityRequest.pb( service.CreateCertificateAuthorityRequest() ) @@ -21553,6 +21643,7 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_certificate_authority( request, @@ -21564,6 +21655,7 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_disable_certificate_authority_rest_bad_request( @@ -21649,11 +21741,15 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_disable_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_disable_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_disable_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.DisableCertificateAuthorityRequest.pb( service.DisableCertificateAuthorityRequest() ) @@ -21677,6 +21773,7 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.disable_certificate_authority( request, @@ -21688,6 +21785,7 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_enable_certificate_authority_rest_bad_request( @@ -21773,11 +21871,15 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_enable_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_enable_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_enable_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.EnableCertificateAuthorityRequest.pb( service.EnableCertificateAuthorityRequest() ) @@ -21801,6 +21903,7 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.enable_certificate_authority( request, @@ -21812,6 +21915,7 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_fetch_certificate_authority_csr_rest_bad_request( @@ -21901,11 +22005,15 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_fetch_certificate_authority_csr", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_fetch_certificate_authority_csr_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_fetch_certificate_authority_csr", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.FetchCertificateAuthorityCsrRequest.pb( service.FetchCertificateAuthorityCsrRequest() ) @@ -21931,6 +22039,10 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.FetchCertificateAuthorityCsrResponse() + post_with_metadata.return_value = ( + service.FetchCertificateAuthorityCsrResponse(), + metadata, + ) client.fetch_certificate_authority_csr( request, @@ -21942,6 +22054,7 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_authority_rest_bad_request( @@ -22041,11 +22154,15 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateAuthorityRequest.pb( service.GetCertificateAuthorityRequest() ) @@ -22071,6 +22188,7 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CertificateAuthority() + post_with_metadata.return_value = resources.CertificateAuthority(), metadata client.get_certificate_authority( request, @@ -22082,6 +22200,7 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificate_authorities_rest_bad_request( @@ -22169,11 +22288,15 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificate_authorities", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificate_authorities_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificate_authorities", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificateAuthoritiesRequest.pb( service.ListCertificateAuthoritiesRequest() ) @@ -22199,6 +22322,10 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificateAuthoritiesResponse() + post_with_metadata.return_value = ( + service.ListCertificateAuthoritiesResponse(), + metadata, + ) client.list_certificate_authorities( request, @@ -22210,6 +22337,7 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_undelete_certificate_authority_rest_bad_request( @@ -22295,11 +22423,15 @@ def test_undelete_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_undelete_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_undelete_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_undelete_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UndeleteCertificateAuthorityRequest.pb( service.UndeleteCertificateAuthorityRequest() ) @@ -22323,6 +22455,7 @@ def test_undelete_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.undelete_certificate_authority( request, @@ -22334,6 +22467,7 @@ def test_undelete_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_certificate_authority_rest_bad_request( @@ -22419,11 +22553,15 @@ def test_delete_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_delete_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_delete_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_delete_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.DeleteCertificateAuthorityRequest.pb( service.DeleteCertificateAuthorityRequest() ) @@ -22447,6 +22585,7 @@ def test_delete_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_certificate_authority( request, @@ -22458,6 +22597,7 @@ def test_delete_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_authority_rest_bad_request( @@ -22772,11 +22912,15 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateAuthorityRequest.pb( service.UpdateCertificateAuthorityRequest() ) @@ -22800,6 +22944,7 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_certificate_authority( request, @@ -22811,6 +22956,7 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_ca_pool_rest_bad_request(request_type=service.CreateCaPoolRequest): @@ -23058,10 +23204,14 @@ def test_create_ca_pool_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_create_ca_pool" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_ca_pool_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_ca_pool" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCaPoolRequest.pb(service.CreateCaPoolRequest()) transcode.return_value = { "method": "post", @@ -23083,6 +23233,7 @@ def test_create_ca_pool_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_ca_pool( request, @@ -23094,6 +23245,7 @@ def test_create_ca_pool_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_ca_pool_rest_bad_request(request_type=service.UpdateCaPoolRequest): @@ -23345,10 +23497,14 @@ def test_update_ca_pool_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_update_ca_pool" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_ca_pool_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_ca_pool" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCaPoolRequest.pb(service.UpdateCaPoolRequest()) transcode.return_value = { "method": "post", @@ -23370,6 +23526,7 @@ def test_update_ca_pool_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_ca_pool( request, @@ -23381,6 +23538,7 @@ def test_update_ca_pool_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_ca_pool_rest_bad_request(request_type=service.GetCaPoolRequest): @@ -23465,10 +23623,14 @@ def test_get_ca_pool_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_get_ca_pool" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_ca_pool_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_ca_pool" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCaPoolRequest.pb(service.GetCaPoolRequest()) transcode.return_value = { "method": "post", @@ -23490,6 +23652,7 @@ def test_get_ca_pool_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CaPool() + post_with_metadata.return_value = resources.CaPool(), metadata client.get_ca_pool( request, @@ -23501,6 +23664,7 @@ def test_get_ca_pool_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_ca_pools_rest_bad_request(request_type=service.ListCaPoolsRequest): @@ -23585,10 +23749,14 @@ def test_list_ca_pools_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_list_ca_pools" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_ca_pools_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_ca_pools" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCaPoolsRequest.pb(service.ListCaPoolsRequest()) transcode.return_value = { "method": "post", @@ -23612,6 +23780,7 @@ def test_list_ca_pools_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCaPoolsResponse() + post_with_metadata.return_value = service.ListCaPoolsResponse(), metadata client.list_ca_pools( request, @@ -23623,6 +23792,7 @@ def test_list_ca_pools_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_ca_pool_rest_bad_request(request_type=service.DeleteCaPoolRequest): @@ -23701,10 +23871,14 @@ def test_delete_ca_pool_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_delete_ca_pool" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_delete_ca_pool_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_delete_ca_pool" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.DeleteCaPoolRequest.pb(service.DeleteCaPoolRequest()) transcode.return_value = { "method": "post", @@ -23726,6 +23900,7 @@ def test_delete_ca_pool_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_ca_pool( request, @@ -23737,6 +23912,7 @@ def test_delete_ca_pool_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_fetch_ca_certs_rest_bad_request(request_type=service.FetchCaCertsRequest): @@ -23816,10 +23992,14 @@ def test_fetch_ca_certs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_fetch_ca_certs" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_fetch_ca_certs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_fetch_ca_certs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.FetchCaCertsRequest.pb(service.FetchCaCertsRequest()) transcode.return_value = { "method": "post", @@ -23843,6 +24023,7 @@ def test_fetch_ca_certs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.FetchCaCertsResponse() + post_with_metadata.return_value = service.FetchCaCertsResponse(), metadata client.fetch_ca_certs( request, @@ -23854,6 +24035,7 @@ def test_fetch_ca_certs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_revocation_list_rest_bad_request( @@ -23953,11 +24135,15 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate_revocation_list", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_revocation_list_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate_revocation_list", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateRevocationListRequest.pb( service.GetCertificateRevocationListRequest() ) @@ -23983,6 +24169,10 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CertificateRevocationList() + post_with_metadata.return_value = ( + resources.CertificateRevocationList(), + metadata, + ) client.get_certificate_revocation_list( request, @@ -23994,6 +24184,7 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificate_revocation_lists_rest_bad_request( @@ -24085,11 +24276,15 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificate_revocation_lists", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificate_revocation_lists_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificate_revocation_lists", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificateRevocationListsRequest.pb( service.ListCertificateRevocationListsRequest() ) @@ -24115,6 +24310,10 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificateRevocationListsResponse() + post_with_metadata.return_value = ( + service.ListCertificateRevocationListsResponse(), + metadata, + ) client.list_certificate_revocation_lists( request, @@ -24126,6 +24325,7 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_revocation_list_rest_bad_request( @@ -24306,11 +24506,15 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate_revocation_list", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_revocation_list_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate_revocation_list", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateRevocationListRequest.pb( service.UpdateCertificateRevocationListRequest() ) @@ -24334,6 +24538,7 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_certificate_revocation_list( request, @@ -24345,6 +24550,7 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_certificate_template_rest_bad_request( @@ -24578,11 +24784,15 @@ def test_create_certificate_template_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_create_certificate_template", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_certificate_template_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_certificate_template", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCertificateTemplateRequest.pb( service.CreateCertificateTemplateRequest() ) @@ -24606,6 +24816,7 @@ def test_create_certificate_template_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_certificate_template( request, @@ -24617,6 +24828,7 @@ def test_create_certificate_template_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_certificate_template_rest_bad_request( @@ -24702,11 +24914,15 @@ def test_delete_certificate_template_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_delete_certificate_template", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_delete_certificate_template_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_delete_certificate_template", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.DeleteCertificateTemplateRequest.pb( service.DeleteCertificateTemplateRequest() ) @@ -24730,6 +24946,7 @@ def test_delete_certificate_template_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_certificate_template( request, @@ -24741,6 +24958,7 @@ def test_delete_certificate_template_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_template_rest_bad_request( @@ -24832,11 +25050,15 @@ def test_get_certificate_template_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate_template", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_template_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate_template", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateTemplateRequest.pb( service.GetCertificateTemplateRequest() ) @@ -24862,6 +25084,7 @@ def test_get_certificate_template_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CertificateTemplate() + post_with_metadata.return_value = resources.CertificateTemplate(), metadata client.get_certificate_template( request, @@ -24873,6 +25096,7 @@ def test_get_certificate_template_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificate_templates_rest_bad_request( @@ -24960,11 +25184,15 @@ def test_list_certificate_templates_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificate_templates", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificate_templates_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificate_templates", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificateTemplatesRequest.pb( service.ListCertificateTemplatesRequest() ) @@ -24990,6 +25218,10 @@ def test_list_certificate_templates_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificateTemplatesResponse() + post_with_metadata.return_value = ( + service.ListCertificateTemplatesResponse(), + metadata, + ) client.list_certificate_templates( request, @@ -25001,6 +25233,7 @@ def test_list_certificate_templates_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_template_rest_bad_request( @@ -25242,11 +25475,15 @@ def test_update_certificate_template_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate_template", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_template_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate_template", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateTemplateRequest.pb( service.UpdateCertificateTemplateRequest() ) @@ -25270,6 +25507,7 @@ def test_update_certificate_template_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_certificate_template( request, @@ -25281,6 +25519,7 @@ def test_update_certificate_template_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1beta1/test_certificate_authority_service.py b/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1beta1/test_certificate_authority_service.py index 6cb3ffdafd03..f3096bdb68bb 100644 --- a/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1beta1/test_certificate_authority_service.py +++ b/packages/google-cloud-private-ca/tests/unit/gapic/privateca_v1beta1/test_certificate_authority_service.py @@ -74,6 +74,13 @@ ) from google.cloud.security.privateca_v1beta1.types import resources, service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -357,6 +364,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -14672,10 +14722,14 @@ def test_create_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_create_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCertificateRequest.pb( service.CreateCertificateRequest() ) @@ -14699,6 +14753,7 @@ def test_create_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.create_certificate( request, @@ -14710,6 +14765,7 @@ def test_create_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_rest_bad_request(request_type=service.GetCertificateRequest): @@ -14801,10 +14857,14 @@ def test_get_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateRequest.pb(service.GetCertificateRequest()) transcode.return_value = { "method": "post", @@ -14826,6 +14886,7 @@ def test_get_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.get_certificate( request, @@ -14837,6 +14898,7 @@ def test_get_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificates_rest_bad_request( @@ -14927,10 +14989,14 @@ def test_list_certificates_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificates" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificates_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificates" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificatesRequest.pb( service.ListCertificatesRequest() ) @@ -14956,6 +15022,7 @@ def test_list_certificates_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificatesResponse() + post_with_metadata.return_value = service.ListCertificatesResponse(), metadata client.list_certificates( request, @@ -14967,6 +15034,7 @@ def test_list_certificates_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_revoke_certificate_rest_bad_request( @@ -15060,10 +15128,14 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_revoke_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_revoke_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_revoke_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.RevokeCertificateRequest.pb( service.RevokeCertificateRequest() ) @@ -15087,6 +15159,7 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.revoke_certificate( request, @@ -15098,6 +15171,7 @@ def test_revoke_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_rest_bad_request( @@ -15371,10 +15445,14 @@ def test_update_certificate_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate" ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateRequest.pb( service.UpdateCertificateRequest() ) @@ -15398,6 +15476,7 @@ def test_update_certificate_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.Certificate() + post_with_metadata.return_value = resources.Certificate(), metadata client.update_certificate( request, @@ -15409,6 +15488,7 @@ def test_update_certificate_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_activate_certificate_authority_rest_bad_request( @@ -15494,11 +15574,15 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_activate_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_activate_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_activate_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ActivateCertificateAuthorityRequest.pb( service.ActivateCertificateAuthorityRequest() ) @@ -15522,6 +15606,7 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.activate_certificate_authority( request, @@ -15533,6 +15618,7 @@ def test_activate_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_certificate_authority_rest_bad_request( @@ -15844,11 +15930,15 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_create_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_create_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_create_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateCertificateAuthorityRequest.pb( service.CreateCertificateAuthorityRequest() ) @@ -15872,6 +15962,7 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_certificate_authority( request, @@ -15883,6 +15974,7 @@ def test_create_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_disable_certificate_authority_rest_bad_request( @@ -15968,11 +16060,15 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_disable_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_disable_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_disable_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.DisableCertificateAuthorityRequest.pb( service.DisableCertificateAuthorityRequest() ) @@ -15996,6 +16092,7 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.disable_certificate_authority( request, @@ -16007,6 +16104,7 @@ def test_disable_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_enable_certificate_authority_rest_bad_request( @@ -16092,11 +16190,15 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_enable_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_enable_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_enable_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.EnableCertificateAuthorityRequest.pb( service.EnableCertificateAuthorityRequest() ) @@ -16120,6 +16222,7 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.enable_certificate_authority( request, @@ -16131,6 +16234,7 @@ def test_enable_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_fetch_certificate_authority_csr_rest_bad_request( @@ -16220,11 +16324,15 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_fetch_certificate_authority_csr", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_fetch_certificate_authority_csr_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_fetch_certificate_authority_csr", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.FetchCertificateAuthorityCsrRequest.pb( service.FetchCertificateAuthorityCsrRequest() ) @@ -16250,6 +16358,10 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.FetchCertificateAuthorityCsrResponse() + post_with_metadata.return_value = ( + service.FetchCertificateAuthorityCsrResponse(), + metadata, + ) client.fetch_certificate_authority_csr( request, @@ -16261,6 +16373,7 @@ def test_fetch_certificate_authority_csr_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_authority_rest_bad_request( @@ -16360,11 +16473,15 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateAuthorityRequest.pb( service.GetCertificateAuthorityRequest() ) @@ -16390,6 +16507,7 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CertificateAuthority() + post_with_metadata.return_value = resources.CertificateAuthority(), metadata client.get_certificate_authority( request, @@ -16401,6 +16519,7 @@ def test_get_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificate_authorities_rest_bad_request( @@ -16488,11 +16607,15 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificate_authorities", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificate_authorities_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificate_authorities", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificateAuthoritiesRequest.pb( service.ListCertificateAuthoritiesRequest() ) @@ -16518,6 +16641,10 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificateAuthoritiesResponse() + post_with_metadata.return_value = ( + service.ListCertificateAuthoritiesResponse(), + metadata, + ) client.list_certificate_authorities( request, @@ -16529,6 +16656,7 @@ def test_list_certificate_authorities_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_restore_certificate_authority_rest_bad_request( @@ -16614,11 +16742,15 @@ def test_restore_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_restore_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_restore_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_restore_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.RestoreCertificateAuthorityRequest.pb( service.RestoreCertificateAuthorityRequest() ) @@ -16642,6 +16774,7 @@ def test_restore_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.restore_certificate_authority( request, @@ -16653,6 +16786,7 @@ def test_restore_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_schedule_delete_certificate_authority_rest_bad_request( @@ -16738,11 +16872,15 @@ def test_schedule_delete_certificate_authority_rest_interceptors(null_intercepto transports.CertificateAuthorityServiceRestInterceptor, "post_schedule_delete_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_schedule_delete_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_schedule_delete_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ScheduleDeleteCertificateAuthorityRequest.pb( service.ScheduleDeleteCertificateAuthorityRequest() ) @@ -16766,6 +16904,7 @@ def test_schedule_delete_certificate_authority_rest_interceptors(null_intercepto ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.schedule_delete_certificate_authority( request, @@ -16777,6 +16916,7 @@ def test_schedule_delete_certificate_authority_rest_interceptors(null_intercepto pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_authority_rest_bad_request( @@ -17096,11 +17236,15 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate_authority", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateAuthorityRequest.pb( service.UpdateCertificateAuthorityRequest() ) @@ -17124,6 +17268,7 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_certificate_authority( request, @@ -17135,6 +17280,7 @@ def test_update_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_certificate_revocation_list_rest_bad_request( @@ -17232,11 +17378,15 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_certificate_revocation_list", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_certificate_revocation_list_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_certificate_revocation_list", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetCertificateRevocationListRequest.pb( service.GetCertificateRevocationListRequest() ) @@ -17262,6 +17412,10 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.CertificateRevocationList() + post_with_metadata.return_value = ( + resources.CertificateRevocationList(), + metadata, + ) client.get_certificate_revocation_list( request, @@ -17273,6 +17427,7 @@ def test_get_certificate_revocation_list_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_certificate_revocation_lists_rest_bad_request( @@ -17364,11 +17519,15 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_certificate_revocation_lists", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_certificate_revocation_lists_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_certificate_revocation_lists", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListCertificateRevocationListsRequest.pb( service.ListCertificateRevocationListsRequest() ) @@ -17394,6 +17553,10 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListCertificateRevocationListsResponse() + post_with_metadata.return_value = ( + service.ListCertificateRevocationListsResponse(), + metadata, + ) client.list_certificate_revocation_lists( request, @@ -17405,6 +17568,7 @@ def test_list_certificate_revocation_lists_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_certificate_revocation_list_rest_bad_request( @@ -17584,11 +17748,15 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_update_certificate_revocation_list", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_update_certificate_revocation_list_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_update_certificate_revocation_list", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.UpdateCertificateRevocationListRequest.pb( service.UpdateCertificateRevocationListRequest() ) @@ -17612,6 +17780,7 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_certificate_revocation_list( request, @@ -17623,6 +17792,7 @@ def test_update_certificate_revocation_list_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_reusable_config_rest_bad_request( @@ -17714,10 +17884,14 @@ def test_get_reusable_config_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_get_reusable_config", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_get_reusable_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_get_reusable_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.GetReusableConfigRequest.pb( service.GetReusableConfigRequest() ) @@ -17741,6 +17915,7 @@ def test_get_reusable_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.ReusableConfig() + post_with_metadata.return_value = resources.ReusableConfig(), metadata client.get_reusable_config( request, @@ -17752,6 +17927,7 @@ def test_get_reusable_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_reusable_configs_rest_bad_request( @@ -17839,11 +18015,15 @@ def test_list_reusable_configs_rest_interceptors(null_interceptor): transports.CertificateAuthorityServiceRestInterceptor, "post_list_reusable_configs", ) as post, mock.patch.object( + transports.CertificateAuthorityServiceRestInterceptor, + "post_list_reusable_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CertificateAuthorityServiceRestInterceptor, "pre_list_reusable_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.ListReusableConfigsRequest.pb( service.ListReusableConfigsRequest() ) @@ -17869,6 +18049,10 @@ def test_list_reusable_configs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = service.ListReusableConfigsResponse() + post_with_metadata.return_value = ( + service.ListReusableConfigsResponse(), + metadata, + ) client.list_reusable_configs( request, @@ -17880,6 +18064,7 @@ def test_list_reusable_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-resource-manager/README.rst b/packages/google-cloud-resource-manager/README.rst index 2fdde75593cc..b28638ac70ea 100644 --- a/packages/google-cloud-resource-manager/README.rst +++ b/packages/google-cloud-resource-manager/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Resource Manager.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Resource Manager.: https://cloud.google.com/resource-manager -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/client.py index 38bccb239b15..738df2385053 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -487,6 +489,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2239,16 +2268,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/transports/rest.py index ea8b18e665ed..06f58a1b0c55 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/folders/transports/rest.py @@ -182,12 +182,35 @@ def post_create_folder( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_create_folder` interceptor runs + before the `post_create_folder_with_metadata` interceptor. """ return response + def post_create_folder_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_create_folder_with_metadata` + interceptor in new development instead of the `post_create_folder` interceptor. + When both interceptors are used, this `post_create_folder_with_metadata` interceptor runs after the + `post_create_folder` interceptor. The (possibly modified) response returned by + `post_create_folder` will be passed to + `post_create_folder_with_metadata`. + """ + return response, metadata + def pre_delete_folder( self, request: folders.DeleteFolderRequest, @@ -205,12 +228,35 @@ def post_delete_folder( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_delete_folder` interceptor runs + before the `post_delete_folder_with_metadata` interceptor. """ return response + def post_delete_folder_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_delete_folder_with_metadata` + interceptor in new development instead of the `post_delete_folder` interceptor. + When both interceptors are used, this `post_delete_folder_with_metadata` interceptor runs after the + `post_delete_folder` interceptor. The (possibly modified) response returned by + `post_delete_folder` will be passed to + `post_delete_folder_with_metadata`. + """ + return response, metadata + def pre_get_folder( self, request: folders.GetFolderRequest, @@ -226,12 +272,35 @@ def pre_get_folder( def post_get_folder(self, response: folders.Folder) -> folders.Folder: """Post-rpc interceptor for get_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_get_folder` interceptor runs + before the `post_get_folder_with_metadata` interceptor. """ return response + def post_get_folder_with_metadata( + self, + response: folders.Folder, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[folders.Folder, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_get_folder_with_metadata` + interceptor in new development instead of the `post_get_folder` interceptor. + When both interceptors are used, this `post_get_folder_with_metadata` interceptor runs after the + `post_get_folder` interceptor. The (possibly modified) response returned by + `post_get_folder` will be passed to + `post_get_folder_with_metadata`. + """ + return response, metadata + def pre_get_iam_policy( self, request: iam_policy_pb2.GetIamPolicyRequest, @@ -249,12 +318,35 @@ def pre_get_iam_policy( def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for get_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_get_iam_policy` interceptor runs + before the `post_get_iam_policy_with_metadata` interceptor. """ return response + def post_get_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_get_iam_policy_with_metadata` + interceptor in new development instead of the `post_get_iam_policy` interceptor. + When both interceptors are used, this `post_get_iam_policy_with_metadata` interceptor runs after the + `post_get_iam_policy` interceptor. The (possibly modified) response returned by + `post_get_iam_policy` will be passed to + `post_get_iam_policy_with_metadata`. + """ + return response, metadata + def pre_list_folders( self, request: folders.ListFoldersRequest, @@ -272,12 +364,35 @@ def post_list_folders( ) -> folders.ListFoldersResponse: """Post-rpc interceptor for list_folders - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_folders_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_list_folders` interceptor runs + before the `post_list_folders_with_metadata` interceptor. """ return response + def post_list_folders_with_metadata( + self, + response: folders.ListFoldersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[folders.ListFoldersResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_folders + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_list_folders_with_metadata` + interceptor in new development instead of the `post_list_folders` interceptor. + When both interceptors are used, this `post_list_folders_with_metadata` interceptor runs after the + `post_list_folders` interceptor. The (possibly modified) response returned by + `post_list_folders` will be passed to + `post_list_folders_with_metadata`. + """ + return response, metadata + def pre_move_folder( self, request: folders.MoveFolderRequest, @@ -295,12 +410,35 @@ def post_move_folder( ) -> operations_pb2.Operation: """Post-rpc interceptor for move_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_move_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_move_folder` interceptor runs + before the `post_move_folder_with_metadata` interceptor. """ return response + def post_move_folder_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for move_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_move_folder_with_metadata` + interceptor in new development instead of the `post_move_folder` interceptor. + When both interceptors are used, this `post_move_folder_with_metadata` interceptor runs after the + `post_move_folder` interceptor. The (possibly modified) response returned by + `post_move_folder` will be passed to + `post_move_folder_with_metadata`. + """ + return response, metadata + def pre_search_folders( self, request: folders.SearchFoldersRequest, @@ -318,12 +456,35 @@ def post_search_folders( ) -> folders.SearchFoldersResponse: """Post-rpc interceptor for search_folders - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_folders_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_search_folders` interceptor runs + before the `post_search_folders_with_metadata` interceptor. """ return response + def post_search_folders_with_metadata( + self, + response: folders.SearchFoldersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[folders.SearchFoldersResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for search_folders + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_search_folders_with_metadata` + interceptor in new development instead of the `post_search_folders` interceptor. + When both interceptors are used, this `post_search_folders_with_metadata` interceptor runs after the + `post_search_folders` interceptor. The (possibly modified) response returned by + `post_search_folders` will be passed to + `post_search_folders_with_metadata`. + """ + return response, metadata + def pre_set_iam_policy( self, request: iam_policy_pb2.SetIamPolicyRequest, @@ -341,12 +502,35 @@ def pre_set_iam_policy( def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for set_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_set_iam_policy` interceptor runs + before the `post_set_iam_policy_with_metadata` interceptor. """ return response + def post_set_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_set_iam_policy_with_metadata` + interceptor in new development instead of the `post_set_iam_policy` interceptor. + When both interceptors are used, this `post_set_iam_policy_with_metadata` interceptor runs after the + `post_set_iam_policy` interceptor. The (possibly modified) response returned by + `post_set_iam_policy` will be passed to + `post_set_iam_policy_with_metadata`. + """ + return response, metadata + def pre_test_iam_permissions( self, request: iam_policy_pb2.TestIamPermissionsRequest, @@ -367,12 +551,38 @@ def post_test_iam_permissions( ) -> iam_policy_pb2.TestIamPermissionsResponse: """Post-rpc interceptor for test_iam_permissions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_test_iam_permissions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_test_iam_permissions` interceptor runs + before the `post_test_iam_permissions_with_metadata` interceptor. """ return response + def post_test_iam_permissions_with_metadata( + self, + response: iam_policy_pb2.TestIamPermissionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + iam_policy_pb2.TestIamPermissionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_test_iam_permissions_with_metadata` + interceptor in new development instead of the `post_test_iam_permissions` interceptor. + When both interceptors are used, this `post_test_iam_permissions_with_metadata` interceptor runs after the + `post_test_iam_permissions` interceptor. The (possibly modified) response returned by + `post_test_iam_permissions` will be passed to + `post_test_iam_permissions_with_metadata`. + """ + return response, metadata + def pre_undelete_folder( self, request: folders.UndeleteFolderRequest, @@ -390,12 +600,35 @@ def post_undelete_folder( ) -> operations_pb2.Operation: """Post-rpc interceptor for undelete_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_undelete_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_undelete_folder` interceptor runs + before the `post_undelete_folder_with_metadata` interceptor. """ return response + def post_undelete_folder_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for undelete_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_undelete_folder_with_metadata` + interceptor in new development instead of the `post_undelete_folder` interceptor. + When both interceptors are used, this `post_undelete_folder_with_metadata` interceptor runs after the + `post_undelete_folder` interceptor. The (possibly modified) response returned by + `post_undelete_folder` will be passed to + `post_undelete_folder_with_metadata`. + """ + return response, metadata + def pre_update_folder( self, request: folders.UpdateFolderRequest, @@ -413,12 +646,35 @@ def post_update_folder( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_folder - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_folder_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Folders server but before - it is returned to user code. + it is returned to user code. This `post_update_folder` interceptor runs + before the `post_update_folder_with_metadata` interceptor. """ return response + def post_update_folder_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_folder + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Folders server but before it is returned to user code. + + We recommend only using this `post_update_folder_with_metadata` + interceptor in new development instead of the `post_update_folder` interceptor. + When both interceptors are used, this `post_update_folder_with_metadata` interceptor runs after the + `post_update_folder` interceptor. The (possibly modified) response returned by + `post_update_folder` will be passed to + `post_update_folder_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -695,6 +951,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -838,6 +1098,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -981,6 +1245,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1204,6 +1472,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1346,6 +1618,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_folders(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_folders_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1493,6 +1769,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_move_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_move_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1638,6 +1918,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_folders(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_folders_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1861,6 +2145,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2009,6 +2297,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_test_iam_permissions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_test_iam_permissions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2160,6 +2452,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_undelete_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_undelete_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2316,6 +2612,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_folder(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_folder_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/client.py index eec927ece34a..5dc69db80531 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -480,6 +482,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1392,16 +1421,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/transports/rest.py index 338156e473b6..1d8b1b11c834 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/organizations/transports/rest.py @@ -134,12 +134,35 @@ def pre_get_iam_policy( def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for get_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Organizations server but before - it is returned to user code. + it is returned to user code. This `post_get_iam_policy` interceptor runs + before the `post_get_iam_policy_with_metadata` interceptor. """ return response + def post_get_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Organizations server but before it is returned to user code. + + We recommend only using this `post_get_iam_policy_with_metadata` + interceptor in new development instead of the `post_get_iam_policy` interceptor. + When both interceptors are used, this `post_get_iam_policy_with_metadata` interceptor runs after the + `post_get_iam_policy` interceptor. The (possibly modified) response returned by + `post_get_iam_policy` will be passed to + `post_get_iam_policy_with_metadata`. + """ + return response, metadata + def pre_get_organization( self, request: organizations.GetOrganizationRequest, @@ -159,12 +182,35 @@ def post_get_organization( ) -> organizations.Organization: """Post-rpc interceptor for get_organization - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_organization_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Organizations server but before - it is returned to user code. + it is returned to user code. This `post_get_organization` interceptor runs + before the `post_get_organization_with_metadata` interceptor. """ return response + def post_get_organization_with_metadata( + self, + response: organizations.Organization, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[organizations.Organization, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_organization + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Organizations server but before it is returned to user code. + + We recommend only using this `post_get_organization_with_metadata` + interceptor in new development instead of the `post_get_organization` interceptor. + When both interceptors are used, this `post_get_organization_with_metadata` interceptor runs after the + `post_get_organization` interceptor. The (possibly modified) response returned by + `post_get_organization` will be passed to + `post_get_organization_with_metadata`. + """ + return response, metadata + def pre_search_organizations( self, request: organizations.SearchOrganizationsRequest, @@ -185,12 +231,38 @@ def post_search_organizations( ) -> organizations.SearchOrganizationsResponse: """Post-rpc interceptor for search_organizations - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_organizations_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Organizations server but before - it is returned to user code. + it is returned to user code. This `post_search_organizations` interceptor runs + before the `post_search_organizations_with_metadata` interceptor. """ return response + def post_search_organizations_with_metadata( + self, + response: organizations.SearchOrganizationsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + organizations.SearchOrganizationsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for search_organizations + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Organizations server but before it is returned to user code. + + We recommend only using this `post_search_organizations_with_metadata` + interceptor in new development instead of the `post_search_organizations` interceptor. + When both interceptors are used, this `post_search_organizations_with_metadata` interceptor runs after the + `post_search_organizations` interceptor. The (possibly modified) response returned by + `post_search_organizations` will be passed to + `post_search_organizations_with_metadata`. + """ + return response, metadata + def pre_set_iam_policy( self, request: iam_policy_pb2.SetIamPolicyRequest, @@ -208,12 +280,35 @@ def pre_set_iam_policy( def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for set_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Organizations server but before - it is returned to user code. + it is returned to user code. This `post_set_iam_policy` interceptor runs + before the `post_set_iam_policy_with_metadata` interceptor. """ return response + def post_set_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Organizations server but before it is returned to user code. + + We recommend only using this `post_set_iam_policy_with_metadata` + interceptor in new development instead of the `post_set_iam_policy` interceptor. + When both interceptors are used, this `post_set_iam_policy_with_metadata` interceptor runs after the + `post_set_iam_policy` interceptor. The (possibly modified) response returned by + `post_set_iam_policy` will be passed to + `post_set_iam_policy_with_metadata`. + """ + return response, metadata + def pre_test_iam_permissions( self, request: iam_policy_pb2.TestIamPermissionsRequest, @@ -234,12 +329,38 @@ def post_test_iam_permissions( ) -> iam_policy_pb2.TestIamPermissionsResponse: """Post-rpc interceptor for test_iam_permissions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_test_iam_permissions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Organizations server but before - it is returned to user code. + it is returned to user code. This `post_test_iam_permissions` interceptor runs + before the `post_test_iam_permissions_with_metadata` interceptor. """ return response + def post_test_iam_permissions_with_metadata( + self, + response: iam_policy_pb2.TestIamPermissionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + iam_policy_pb2.TestIamPermissionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Organizations server but before it is returned to user code. + + We recommend only using this `post_test_iam_permissions_with_metadata` + interceptor in new development instead of the `post_test_iam_permissions` interceptor. + When both interceptors are used, this `post_test_iam_permissions_with_metadata` interceptor runs after the + `post_test_iam_permissions` interceptor. The (possibly modified) response returned by + `post_test_iam_permissions` will be passed to + `post_test_iam_permissions_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -550,6 +671,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -698,6 +823,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_organization(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_organization_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -842,6 +971,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_organizations(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_organizations_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1065,6 +1198,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1213,6 +1350,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_test_iam_permissions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_test_iam_permissions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/client.py index 9f50334b832e..cab93580f57a 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2295,16 +2324,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/transports/rest.py index 55312200c880..55fb98bc80fa 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/projects/transports/rest.py @@ -182,12 +182,35 @@ def post_create_project( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_create_project` interceptor runs + before the `post_create_project_with_metadata` interceptor. """ return response + def post_create_project_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_create_project_with_metadata` + interceptor in new development instead of the `post_create_project` interceptor. + When both interceptors are used, this `post_create_project_with_metadata` interceptor runs after the + `post_create_project` interceptor. The (possibly modified) response returned by + `post_create_project` will be passed to + `post_create_project_with_metadata`. + """ + return response, metadata + def pre_delete_project( self, request: projects.DeleteProjectRequest, @@ -205,12 +228,35 @@ def post_delete_project( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_delete_project` interceptor runs + before the `post_delete_project_with_metadata` interceptor. """ return response + def post_delete_project_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_delete_project_with_metadata` + interceptor in new development instead of the `post_delete_project` interceptor. + When both interceptors are used, this `post_delete_project_with_metadata` interceptor runs after the + `post_delete_project` interceptor. The (possibly modified) response returned by + `post_delete_project` will be passed to + `post_delete_project_with_metadata`. + """ + return response, metadata + def pre_get_iam_policy( self, request: iam_policy_pb2.GetIamPolicyRequest, @@ -228,12 +274,35 @@ def pre_get_iam_policy( def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for get_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_get_iam_policy` interceptor runs + before the `post_get_iam_policy_with_metadata` interceptor. """ return response + def post_get_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_get_iam_policy_with_metadata` + interceptor in new development instead of the `post_get_iam_policy` interceptor. + When both interceptors are used, this `post_get_iam_policy_with_metadata` interceptor runs after the + `post_get_iam_policy` interceptor. The (possibly modified) response returned by + `post_get_iam_policy` will be passed to + `post_get_iam_policy_with_metadata`. + """ + return response, metadata + def pre_get_project( self, request: projects.GetProjectRequest, @@ -249,12 +318,35 @@ def pre_get_project( def post_get_project(self, response: projects.Project) -> projects.Project: """Post-rpc interceptor for get_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_get_project` interceptor runs + before the `post_get_project_with_metadata` interceptor. """ return response + def post_get_project_with_metadata( + self, + response: projects.Project, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[projects.Project, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_get_project_with_metadata` + interceptor in new development instead of the `post_get_project` interceptor. + When both interceptors are used, this `post_get_project_with_metadata` interceptor runs after the + `post_get_project` interceptor. The (possibly modified) response returned by + `post_get_project` will be passed to + `post_get_project_with_metadata`. + """ + return response, metadata + def pre_list_projects( self, request: projects.ListProjectsRequest, @@ -272,12 +364,35 @@ def post_list_projects( ) -> projects.ListProjectsResponse: """Post-rpc interceptor for list_projects - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_projects_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_list_projects` interceptor runs + before the `post_list_projects_with_metadata` interceptor. """ return response + def post_list_projects_with_metadata( + self, + response: projects.ListProjectsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[projects.ListProjectsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_projects + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_list_projects_with_metadata` + interceptor in new development instead of the `post_list_projects` interceptor. + When both interceptors are used, this `post_list_projects_with_metadata` interceptor runs after the + `post_list_projects` interceptor. The (possibly modified) response returned by + `post_list_projects` will be passed to + `post_list_projects_with_metadata`. + """ + return response, metadata + def pre_move_project( self, request: projects.MoveProjectRequest, @@ -295,12 +410,35 @@ def post_move_project( ) -> operations_pb2.Operation: """Post-rpc interceptor for move_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_move_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_move_project` interceptor runs + before the `post_move_project_with_metadata` interceptor. """ return response + def post_move_project_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for move_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_move_project_with_metadata` + interceptor in new development instead of the `post_move_project` interceptor. + When both interceptors are used, this `post_move_project_with_metadata` interceptor runs after the + `post_move_project` interceptor. The (possibly modified) response returned by + `post_move_project` will be passed to + `post_move_project_with_metadata`. + """ + return response, metadata + def pre_search_projects( self, request: projects.SearchProjectsRequest, @@ -318,12 +456,37 @@ def post_search_projects( ) -> projects.SearchProjectsResponse: """Post-rpc interceptor for search_projects - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_projects_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_search_projects` interceptor runs + before the `post_search_projects_with_metadata` interceptor. """ return response + def post_search_projects_with_metadata( + self, + response: projects.SearchProjectsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + projects.SearchProjectsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for search_projects + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_search_projects_with_metadata` + interceptor in new development instead of the `post_search_projects` interceptor. + When both interceptors are used, this `post_search_projects_with_metadata` interceptor runs after the + `post_search_projects` interceptor. The (possibly modified) response returned by + `post_search_projects` will be passed to + `post_search_projects_with_metadata`. + """ + return response, metadata + def pre_set_iam_policy( self, request: iam_policy_pb2.SetIamPolicyRequest, @@ -341,12 +504,35 @@ def pre_set_iam_policy( def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for set_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_set_iam_policy` interceptor runs + before the `post_set_iam_policy_with_metadata` interceptor. """ return response + def post_set_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_set_iam_policy_with_metadata` + interceptor in new development instead of the `post_set_iam_policy` interceptor. + When both interceptors are used, this `post_set_iam_policy_with_metadata` interceptor runs after the + `post_set_iam_policy` interceptor. The (possibly modified) response returned by + `post_set_iam_policy` will be passed to + `post_set_iam_policy_with_metadata`. + """ + return response, metadata + def pre_test_iam_permissions( self, request: iam_policy_pb2.TestIamPermissionsRequest, @@ -367,12 +553,38 @@ def post_test_iam_permissions( ) -> iam_policy_pb2.TestIamPermissionsResponse: """Post-rpc interceptor for test_iam_permissions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_test_iam_permissions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_test_iam_permissions` interceptor runs + before the `post_test_iam_permissions_with_metadata` interceptor. """ return response + def post_test_iam_permissions_with_metadata( + self, + response: iam_policy_pb2.TestIamPermissionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + iam_policy_pb2.TestIamPermissionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_test_iam_permissions_with_metadata` + interceptor in new development instead of the `post_test_iam_permissions` interceptor. + When both interceptors are used, this `post_test_iam_permissions_with_metadata` interceptor runs after the + `post_test_iam_permissions` interceptor. The (possibly modified) response returned by + `post_test_iam_permissions` will be passed to + `post_test_iam_permissions_with_metadata`. + """ + return response, metadata + def pre_undelete_project( self, request: projects.UndeleteProjectRequest, @@ -392,12 +604,35 @@ def post_undelete_project( ) -> operations_pb2.Operation: """Post-rpc interceptor for undelete_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_undelete_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_undelete_project` interceptor runs + before the `post_undelete_project_with_metadata` interceptor. """ return response + def post_undelete_project_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for undelete_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_undelete_project_with_metadata` + interceptor in new development instead of the `post_undelete_project` interceptor. + When both interceptors are used, this `post_undelete_project_with_metadata` interceptor runs after the + `post_undelete_project` interceptor. The (possibly modified) response returned by + `post_undelete_project` will be passed to + `post_undelete_project_with_metadata`. + """ + return response, metadata + def pre_update_project( self, request: projects.UpdateProjectRequest, @@ -415,12 +650,35 @@ def post_update_project( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Projects server but before - it is returned to user code. + it is returned to user code. This `post_update_project` interceptor runs + before the `post_update_project_with_metadata` interceptor. """ return response + def post_update_project_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Projects server but before it is returned to user code. + + We recommend only using this `post_update_project_with_metadata` + interceptor in new development instead of the `post_update_project` interceptor. + When both interceptors are used, this `post_update_project_with_metadata` interceptor runs after the + `post_update_project` interceptor. The (possibly modified) response returned by + `post_update_project` will be passed to + `post_update_project_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -698,6 +956,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -844,6 +1106,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1067,6 +1333,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1215,6 +1485,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1370,6 +1644,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_projects(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_projects_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1521,6 +1799,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_move_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_move_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1674,6 +1956,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_projects(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_projects_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1897,6 +2183,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2045,6 +2335,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_test_iam_permissions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_test_iam_permissions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2202,6 +2496,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_undelete_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_undelete_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2360,6 +2658,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/client.py index 72886ad92428..c1eb995e72b2 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -513,6 +515,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1244,16 +1273,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/transports/rest.py index da6ad505f359..8831353800cc 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_bindings/transports/rest.py @@ -126,12 +126,35 @@ def post_create_tag_binding( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_tag_binding - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_tag_binding_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagBindings server but before - it is returned to user code. + it is returned to user code. This `post_create_tag_binding` interceptor runs + before the `post_create_tag_binding_with_metadata` interceptor. """ return response + def post_create_tag_binding_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_tag_binding + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagBindings server but before it is returned to user code. + + We recommend only using this `post_create_tag_binding_with_metadata` + interceptor in new development instead of the `post_create_tag_binding` interceptor. + When both interceptors are used, this `post_create_tag_binding_with_metadata` interceptor runs after the + `post_create_tag_binding` interceptor. The (possibly modified) response returned by + `post_create_tag_binding` will be passed to + `post_create_tag_binding_with_metadata`. + """ + return response, metadata + def pre_delete_tag_binding( self, request: tag_bindings.DeleteTagBindingRequest, @@ -151,12 +174,35 @@ def post_delete_tag_binding( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_tag_binding - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_tag_binding_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagBindings server but before - it is returned to user code. + it is returned to user code. This `post_delete_tag_binding` interceptor runs + before the `post_delete_tag_binding_with_metadata` interceptor. """ return response + def post_delete_tag_binding_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_tag_binding + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagBindings server but before it is returned to user code. + + We recommend only using this `post_delete_tag_binding_with_metadata` + interceptor in new development instead of the `post_delete_tag_binding` interceptor. + When both interceptors are used, this `post_delete_tag_binding_with_metadata` interceptor runs after the + `post_delete_tag_binding` interceptor. The (possibly modified) response returned by + `post_delete_tag_binding` will be passed to + `post_delete_tag_binding_with_metadata`. + """ + return response, metadata + def pre_list_effective_tags( self, request: tag_bindings.ListEffectiveTagsRequest, @@ -176,12 +222,37 @@ def post_list_effective_tags( ) -> tag_bindings.ListEffectiveTagsResponse: """Post-rpc interceptor for list_effective_tags - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_effective_tags_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagBindings server but before - it is returned to user code. + it is returned to user code. This `post_list_effective_tags` interceptor runs + before the `post_list_effective_tags_with_metadata` interceptor. """ return response + def post_list_effective_tags_with_metadata( + self, + response: tag_bindings.ListEffectiveTagsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + tag_bindings.ListEffectiveTagsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_effective_tags + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagBindings server but before it is returned to user code. + + We recommend only using this `post_list_effective_tags_with_metadata` + interceptor in new development instead of the `post_list_effective_tags` interceptor. + When both interceptors are used, this `post_list_effective_tags_with_metadata` interceptor runs after the + `post_list_effective_tags` interceptor. The (possibly modified) response returned by + `post_list_effective_tags` will be passed to + `post_list_effective_tags_with_metadata`. + """ + return response, metadata + def pre_list_tag_bindings( self, request: tag_bindings.ListTagBindingsRequest, @@ -201,12 +272,37 @@ def post_list_tag_bindings( ) -> tag_bindings.ListTagBindingsResponse: """Post-rpc interceptor for list_tag_bindings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_tag_bindings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagBindings server but before - it is returned to user code. + it is returned to user code. This `post_list_tag_bindings` interceptor runs + before the `post_list_tag_bindings_with_metadata` interceptor. """ return response + def post_list_tag_bindings_with_metadata( + self, + response: tag_bindings.ListTagBindingsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + tag_bindings.ListTagBindingsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_tag_bindings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagBindings server but before it is returned to user code. + + We recommend only using this `post_list_tag_bindings_with_metadata` + interceptor in new development instead of the `post_list_tag_bindings` interceptor. + When both interceptors are used, this `post_list_tag_bindings_with_metadata` interceptor runs after the + `post_list_tag_bindings` interceptor. The (possibly modified) response returned by + `post_list_tag_bindings` will be passed to + `post_list_tag_bindings_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -483,6 +579,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_tag_binding(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_tag_binding_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -627,6 +727,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_tag_binding(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_tag_binding_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -770,6 +874,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_effective_tags(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_effective_tags_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -915,6 +1023,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_tag_bindings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_tag_bindings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/client.py index 1b12b6948881..4507c4268395 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -488,6 +490,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1121,16 +1150,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/transports/rest.py index 483d926d7b84..464049616e72 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_holds/transports/rest.py @@ -116,12 +116,35 @@ def post_create_tag_hold( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_tag_hold - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_tag_hold_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagHolds server but before - it is returned to user code. + it is returned to user code. This `post_create_tag_hold` interceptor runs + before the `post_create_tag_hold_with_metadata` interceptor. """ return response + def post_create_tag_hold_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_tag_hold + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagHolds server but before it is returned to user code. + + We recommend only using this `post_create_tag_hold_with_metadata` + interceptor in new development instead of the `post_create_tag_hold` interceptor. + When both interceptors are used, this `post_create_tag_hold_with_metadata` interceptor runs after the + `post_create_tag_hold` interceptor. The (possibly modified) response returned by + `post_create_tag_hold` will be passed to + `post_create_tag_hold_with_metadata`. + """ + return response, metadata + def pre_delete_tag_hold( self, request: tag_holds.DeleteTagHoldRequest, @@ -139,12 +162,35 @@ def post_delete_tag_hold( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_tag_hold - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_tag_hold_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagHolds server but before - it is returned to user code. + it is returned to user code. This `post_delete_tag_hold` interceptor runs + before the `post_delete_tag_hold_with_metadata` interceptor. """ return response + def post_delete_tag_hold_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_tag_hold + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagHolds server but before it is returned to user code. + + We recommend only using this `post_delete_tag_hold_with_metadata` + interceptor in new development instead of the `post_delete_tag_hold` interceptor. + When both interceptors are used, this `post_delete_tag_hold_with_metadata` interceptor runs after the + `post_delete_tag_hold` interceptor. The (possibly modified) response returned by + `post_delete_tag_hold` will be passed to + `post_delete_tag_hold_with_metadata`. + """ + return response, metadata + def pre_list_tag_holds( self, request: tag_holds.ListTagHoldsRequest, @@ -162,12 +208,35 @@ def post_list_tag_holds( ) -> tag_holds.ListTagHoldsResponse: """Post-rpc interceptor for list_tag_holds - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_tag_holds_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagHolds server but before - it is returned to user code. + it is returned to user code. This `post_list_tag_holds` interceptor runs + before the `post_list_tag_holds_with_metadata` interceptor. """ return response + def post_list_tag_holds_with_metadata( + self, + response: tag_holds.ListTagHoldsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_holds.ListTagHoldsResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_tag_holds + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagHolds server but before it is returned to user code. + + We recommend only using this `post_list_tag_holds_with_metadata` + interceptor in new development instead of the `post_list_tag_holds` interceptor. + When both interceptors are used, this `post_list_tag_holds_with_metadata` interceptor runs after the + `post_list_tag_holds` interceptor. The (possibly modified) response returned by + `post_list_tag_holds` will be passed to + `post_list_tag_holds_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -449,6 +518,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_tag_hold(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_tag_hold_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -595,6 +668,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_tag_hold(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_tag_hold_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -738,6 +815,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_tag_holds(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_tag_holds_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/client.py index 0a5bcb8828d7..b4b01b920950 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1849,16 +1878,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/transports/rest.py index 33d03a329e50..d3f0a366944c 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_keys/transports/rest.py @@ -166,12 +166,35 @@ def post_create_tag_key( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_tag_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_tag_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_create_tag_key` interceptor runs + before the `post_create_tag_key_with_metadata` interceptor. """ return response + def post_create_tag_key_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_tag_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_create_tag_key_with_metadata` + interceptor in new development instead of the `post_create_tag_key` interceptor. + When both interceptors are used, this `post_create_tag_key_with_metadata` interceptor runs after the + `post_create_tag_key` interceptor. The (possibly modified) response returned by + `post_create_tag_key` will be passed to + `post_create_tag_key_with_metadata`. + """ + return response, metadata + def pre_delete_tag_key( self, request: tag_keys.DeleteTagKeyRequest, @@ -189,12 +212,35 @@ def post_delete_tag_key( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_tag_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_tag_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_delete_tag_key` interceptor runs + before the `post_delete_tag_key_with_metadata` interceptor. """ return response + def post_delete_tag_key_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_tag_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_delete_tag_key_with_metadata` + interceptor in new development instead of the `post_delete_tag_key` interceptor. + When both interceptors are used, this `post_delete_tag_key_with_metadata` interceptor runs after the + `post_delete_tag_key` interceptor. The (possibly modified) response returned by + `post_delete_tag_key` will be passed to + `post_delete_tag_key_with_metadata`. + """ + return response, metadata + def pre_get_iam_policy( self, request: iam_policy_pb2.GetIamPolicyRequest, @@ -212,12 +258,35 @@ def pre_get_iam_policy( def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for get_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_get_iam_policy` interceptor runs + before the `post_get_iam_policy_with_metadata` interceptor. """ return response + def post_get_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_get_iam_policy_with_metadata` + interceptor in new development instead of the `post_get_iam_policy` interceptor. + When both interceptors are used, this `post_get_iam_policy_with_metadata` interceptor runs after the + `post_get_iam_policy` interceptor. The (possibly modified) response returned by + `post_get_iam_policy` will be passed to + `post_get_iam_policy_with_metadata`. + """ + return response, metadata + def pre_get_namespaced_tag_key( self, request: tag_keys.GetNamespacedTagKeyRequest, @@ -235,12 +304,35 @@ def pre_get_namespaced_tag_key( def post_get_namespaced_tag_key(self, response: tag_keys.TagKey) -> tag_keys.TagKey: """Post-rpc interceptor for get_namespaced_tag_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_namespaced_tag_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_get_namespaced_tag_key` interceptor runs + before the `post_get_namespaced_tag_key_with_metadata` interceptor. """ return response + def post_get_namespaced_tag_key_with_metadata( + self, + response: tag_keys.TagKey, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_keys.TagKey, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_namespaced_tag_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_get_namespaced_tag_key_with_metadata` + interceptor in new development instead of the `post_get_namespaced_tag_key` interceptor. + When both interceptors are used, this `post_get_namespaced_tag_key_with_metadata` interceptor runs after the + `post_get_namespaced_tag_key` interceptor. The (possibly modified) response returned by + `post_get_namespaced_tag_key` will be passed to + `post_get_namespaced_tag_key_with_metadata`. + """ + return response, metadata + def pre_get_tag_key( self, request: tag_keys.GetTagKeyRequest, @@ -256,12 +348,35 @@ def pre_get_tag_key( def post_get_tag_key(self, response: tag_keys.TagKey) -> tag_keys.TagKey: """Post-rpc interceptor for get_tag_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_tag_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_get_tag_key` interceptor runs + before the `post_get_tag_key_with_metadata` interceptor. """ return response + def post_get_tag_key_with_metadata( + self, + response: tag_keys.TagKey, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_keys.TagKey, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_tag_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_get_tag_key_with_metadata` + interceptor in new development instead of the `post_get_tag_key` interceptor. + When both interceptors are used, this `post_get_tag_key_with_metadata` interceptor runs after the + `post_get_tag_key` interceptor. The (possibly modified) response returned by + `post_get_tag_key` will be passed to + `post_get_tag_key_with_metadata`. + """ + return response, metadata + def pre_list_tag_keys( self, request: tag_keys.ListTagKeysRequest, @@ -279,12 +394,35 @@ def post_list_tag_keys( ) -> tag_keys.ListTagKeysResponse: """Post-rpc interceptor for list_tag_keys - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_tag_keys_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_list_tag_keys` interceptor runs + before the `post_list_tag_keys_with_metadata` interceptor. """ return response + def post_list_tag_keys_with_metadata( + self, + response: tag_keys.ListTagKeysResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_keys.ListTagKeysResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for list_tag_keys + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_list_tag_keys_with_metadata` + interceptor in new development instead of the `post_list_tag_keys` interceptor. + When both interceptors are used, this `post_list_tag_keys_with_metadata` interceptor runs after the + `post_list_tag_keys` interceptor. The (possibly modified) response returned by + `post_list_tag_keys` will be passed to + `post_list_tag_keys_with_metadata`. + """ + return response, metadata + def pre_set_iam_policy( self, request: iam_policy_pb2.SetIamPolicyRequest, @@ -302,12 +440,35 @@ def pre_set_iam_policy( def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for set_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_set_iam_policy` interceptor runs + before the `post_set_iam_policy_with_metadata` interceptor. """ return response + def post_set_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_set_iam_policy_with_metadata` + interceptor in new development instead of the `post_set_iam_policy` interceptor. + When both interceptors are used, this `post_set_iam_policy_with_metadata` interceptor runs after the + `post_set_iam_policy` interceptor. The (possibly modified) response returned by + `post_set_iam_policy` will be passed to + `post_set_iam_policy_with_metadata`. + """ + return response, metadata + def pre_test_iam_permissions( self, request: iam_policy_pb2.TestIamPermissionsRequest, @@ -328,12 +489,38 @@ def post_test_iam_permissions( ) -> iam_policy_pb2.TestIamPermissionsResponse: """Post-rpc interceptor for test_iam_permissions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_test_iam_permissions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_test_iam_permissions` interceptor runs + before the `post_test_iam_permissions_with_metadata` interceptor. """ return response + def post_test_iam_permissions_with_metadata( + self, + response: iam_policy_pb2.TestIamPermissionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + iam_policy_pb2.TestIamPermissionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_test_iam_permissions_with_metadata` + interceptor in new development instead of the `post_test_iam_permissions` interceptor. + When both interceptors are used, this `post_test_iam_permissions_with_metadata` interceptor runs after the + `post_test_iam_permissions` interceptor. The (possibly modified) response returned by + `post_test_iam_permissions` will be passed to + `post_test_iam_permissions_with_metadata`. + """ + return response, metadata + def pre_update_tag_key( self, request: tag_keys.UpdateTagKeyRequest, @@ -351,12 +538,35 @@ def post_update_tag_key( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_tag_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_tag_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagKeys server but before - it is returned to user code. + it is returned to user code. This `post_update_tag_key` interceptor runs + before the `post_update_tag_key_with_metadata` interceptor. """ return response + def post_update_tag_key_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_tag_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagKeys server but before it is returned to user code. + + We recommend only using this `post_update_tag_key_with_metadata` + interceptor in new development instead of the `post_update_tag_key` interceptor. + When both interceptors are used, this `post_update_tag_key_with_metadata` interceptor runs after the + `post_update_tag_key` interceptor. The (possibly modified) response returned by + `post_update_tag_key` will be passed to + `post_update_tag_key_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -631,6 +841,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_tag_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_tag_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -775,6 +989,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_tag_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_tag_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -998,6 +1216,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1143,6 +1365,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_namespaced_tag_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_namespaced_tag_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1286,6 +1512,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_tag_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_tag_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1429,6 +1659,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_tag_keys(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_tag_keys_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1652,6 +1886,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1800,6 +2038,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_test_iam_permissions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_test_iam_permissions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1950,6 +2192,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_tag_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_tag_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/client.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/client.py index fd081c6cd176..7b012aedc7b0 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/client.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -483,6 +485,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1856,16 +1885,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/transports/rest.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/transports/rest.py index bad4838b1c73..607da88b926c 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/transports/rest.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/services/tag_values/transports/rest.py @@ -168,12 +168,35 @@ def post_create_tag_value( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_tag_value - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_tag_value_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_create_tag_value` interceptor runs + before the `post_create_tag_value_with_metadata` interceptor. """ return response + def post_create_tag_value_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_tag_value + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_create_tag_value_with_metadata` + interceptor in new development instead of the `post_create_tag_value` interceptor. + When both interceptors are used, this `post_create_tag_value_with_metadata` interceptor runs after the + `post_create_tag_value` interceptor. The (possibly modified) response returned by + `post_create_tag_value` will be passed to + `post_create_tag_value_with_metadata`. + """ + return response, metadata + def pre_delete_tag_value( self, request: tag_values.DeleteTagValueRequest, @@ -193,12 +216,35 @@ def post_delete_tag_value( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_tag_value - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_tag_value_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_delete_tag_value` interceptor runs + before the `post_delete_tag_value_with_metadata` interceptor. """ return response + def post_delete_tag_value_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_tag_value + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_delete_tag_value_with_metadata` + interceptor in new development instead of the `post_delete_tag_value` interceptor. + When both interceptors are used, this `post_delete_tag_value_with_metadata` interceptor runs after the + `post_delete_tag_value` interceptor. The (possibly modified) response returned by + `post_delete_tag_value` will be passed to + `post_delete_tag_value_with_metadata`. + """ + return response, metadata + def pre_get_iam_policy( self, request: iam_policy_pb2.GetIamPolicyRequest, @@ -216,12 +262,35 @@ def pre_get_iam_policy( def post_get_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for get_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_get_iam_policy` interceptor runs + before the `post_get_iam_policy_with_metadata` interceptor. """ return response + def post_get_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_get_iam_policy_with_metadata` + interceptor in new development instead of the `post_get_iam_policy` interceptor. + When both interceptors are used, this `post_get_iam_policy_with_metadata` interceptor runs after the + `post_get_iam_policy` interceptor. The (possibly modified) response returned by + `post_get_iam_policy` will be passed to + `post_get_iam_policy_with_metadata`. + """ + return response, metadata + def pre_get_namespaced_tag_value( self, request: tag_values.GetNamespacedTagValueRequest, @@ -241,12 +310,35 @@ def post_get_namespaced_tag_value( ) -> tag_values.TagValue: """Post-rpc interceptor for get_namespaced_tag_value - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_namespaced_tag_value_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_get_namespaced_tag_value` interceptor runs + before the `post_get_namespaced_tag_value_with_metadata` interceptor. """ return response + def post_get_namespaced_tag_value_with_metadata( + self, + response: tag_values.TagValue, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_values.TagValue, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_namespaced_tag_value + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_get_namespaced_tag_value_with_metadata` + interceptor in new development instead of the `post_get_namespaced_tag_value` interceptor. + When both interceptors are used, this `post_get_namespaced_tag_value_with_metadata` interceptor runs after the + `post_get_namespaced_tag_value` interceptor. The (possibly modified) response returned by + `post_get_namespaced_tag_value` will be passed to + `post_get_namespaced_tag_value_with_metadata`. + """ + return response, metadata + def pre_get_tag_value( self, request: tag_values.GetTagValueRequest, @@ -262,12 +354,35 @@ def pre_get_tag_value( def post_get_tag_value(self, response: tag_values.TagValue) -> tag_values.TagValue: """Post-rpc interceptor for get_tag_value - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_tag_value_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_get_tag_value` interceptor runs + before the `post_get_tag_value_with_metadata` interceptor. """ return response + def post_get_tag_value_with_metadata( + self, + response: tag_values.TagValue, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[tag_values.TagValue, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_tag_value + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_get_tag_value_with_metadata` + interceptor in new development instead of the `post_get_tag_value` interceptor. + When both interceptors are used, this `post_get_tag_value_with_metadata` interceptor runs after the + `post_get_tag_value` interceptor. The (possibly modified) response returned by + `post_get_tag_value` will be passed to + `post_get_tag_value_with_metadata`. + """ + return response, metadata + def pre_list_tag_values( self, request: tag_values.ListTagValuesRequest, @@ -287,12 +402,37 @@ def post_list_tag_values( ) -> tag_values.ListTagValuesResponse: """Post-rpc interceptor for list_tag_values - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_tag_values_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_list_tag_values` interceptor runs + before the `post_list_tag_values_with_metadata` interceptor. """ return response + def post_list_tag_values_with_metadata( + self, + response: tag_values.ListTagValuesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + tag_values.ListTagValuesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_tag_values + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_list_tag_values_with_metadata` + interceptor in new development instead of the `post_list_tag_values` interceptor. + When both interceptors are used, this `post_list_tag_values_with_metadata` interceptor runs after the + `post_list_tag_values` interceptor. The (possibly modified) response returned by + `post_list_tag_values` will be passed to + `post_list_tag_values_with_metadata`. + """ + return response, metadata + def pre_set_iam_policy( self, request: iam_policy_pb2.SetIamPolicyRequest, @@ -310,12 +450,35 @@ def pre_set_iam_policy( def post_set_iam_policy(self, response: policy_pb2.Policy) -> policy_pb2.Policy: """Post-rpc interceptor for set_iam_policy - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_iam_policy_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_set_iam_policy` interceptor runs + before the `post_set_iam_policy_with_metadata` interceptor. """ return response + def post_set_iam_policy_with_metadata( + self, + response: policy_pb2.Policy, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[policy_pb2.Policy, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_iam_policy + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_set_iam_policy_with_metadata` + interceptor in new development instead of the `post_set_iam_policy` interceptor. + When both interceptors are used, this `post_set_iam_policy_with_metadata` interceptor runs after the + `post_set_iam_policy` interceptor. The (possibly modified) response returned by + `post_set_iam_policy` will be passed to + `post_set_iam_policy_with_metadata`. + """ + return response, metadata + def pre_test_iam_permissions( self, request: iam_policy_pb2.TestIamPermissionsRequest, @@ -336,12 +499,38 @@ def post_test_iam_permissions( ) -> iam_policy_pb2.TestIamPermissionsResponse: """Post-rpc interceptor for test_iam_permissions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_test_iam_permissions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_test_iam_permissions` interceptor runs + before the `post_test_iam_permissions_with_metadata` interceptor. """ return response + def post_test_iam_permissions_with_metadata( + self, + response: iam_policy_pb2.TestIamPermissionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + iam_policy_pb2.TestIamPermissionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for test_iam_permissions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_test_iam_permissions_with_metadata` + interceptor in new development instead of the `post_test_iam_permissions` interceptor. + When both interceptors are used, this `post_test_iam_permissions_with_metadata` interceptor runs after the + `post_test_iam_permissions` interceptor. The (possibly modified) response returned by + `post_test_iam_permissions` will be passed to + `post_test_iam_permissions_with_metadata`. + """ + return response, metadata + def pre_update_tag_value( self, request: tag_values.UpdateTagValueRequest, @@ -361,12 +550,35 @@ def post_update_tag_value( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_tag_value - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_tag_value_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the TagValues server but before - it is returned to user code. + it is returned to user code. This `post_update_tag_value` interceptor runs + before the `post_update_tag_value_with_metadata` interceptor. """ return response + def post_update_tag_value_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_tag_value + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the TagValues server but before it is returned to user code. + + We recommend only using this `post_update_tag_value_with_metadata` + interceptor in new development instead of the `post_update_tag_value` interceptor. + When both interceptors are used, this `post_update_tag_value_with_metadata` interceptor runs after the + `post_update_tag_value` interceptor. The (possibly modified) response returned by + `post_update_tag_value` will be passed to + `post_update_tag_value_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -647,6 +859,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_tag_value(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_tag_value_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -795,6 +1011,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_tag_value(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_tag_value_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1020,6 +1240,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1167,6 +1391,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_namespaced_tag_value(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_namespaced_tag_value_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1314,6 +1542,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_tag_value(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_tag_value_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1461,6 +1693,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_tag_values(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_tag_values_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1688,6 +1924,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_iam_policy(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_iam_policy_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1836,6 +2076,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_test_iam_permissions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_test_iam_permissions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1992,6 +2236,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_tag_value(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_tag_value_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-manager/noxfile.py b/packages/google-cloud-resource-manager/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-resource-manager/noxfile.py +++ b/packages/google-cloud-resource-manager/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json b/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json index 68149d644114..18bac0c91496 100644 --- a/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json +++ b/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-resource-manager", - "version": "1.14.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-resource-manager/setup.py b/packages/google-cloud-resource-manager/setup.py index cb4b232baa9e..0d6d4718b8cc 100644 --- a/packages/google-cloud-resource-manager/setup.py +++ b/packages/google-cloud-resource-manager/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-resource-manager" diff --git a/packages/google-cloud-resource-manager/testing/constraints-3.7.txt b/packages/google-cloud-resource-manager/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-resource-manager/testing/constraints-3.7.txt +++ b/packages/google-cloud-resource-manager/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_folders.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_folders.py index 5142b5a5fa6c..0cd4c7bc6aa2 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_folders.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_folders.py @@ -76,6 +76,13 @@ ) from google.cloud.resourcemanager_v3.types import folders +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -299,6 +306,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = FoldersClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = FoldersClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7655,10 +7705,13 @@ def test_get_folder_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_get_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_get_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_get_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.GetFolderRequest.pb(folders.GetFolderRequest()) transcode.return_value = { "method": "post", @@ -7680,6 +7733,7 @@ def test_get_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = folders.Folder() + post_with_metadata.return_value = folders.Folder(), metadata client.get_folder( request, @@ -7691,6 +7745,7 @@ def test_get_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_folders_rest_bad_request(request_type=folders.ListFoldersRequest): @@ -7771,10 +7826,13 @@ def test_list_folders_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_list_folders" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_list_folders_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_list_folders" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.ListFoldersRequest.pb(folders.ListFoldersRequest()) transcode.return_value = { "method": "post", @@ -7798,6 +7856,7 @@ def test_list_folders_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = folders.ListFoldersResponse() + post_with_metadata.return_value = folders.ListFoldersResponse(), metadata client.list_folders( request, @@ -7809,6 +7868,7 @@ def test_list_folders_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_folders_rest_bad_request(request_type=folders.SearchFoldersRequest): @@ -7889,10 +7949,13 @@ def test_search_folders_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_search_folders" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_search_folders_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_search_folders" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.SearchFoldersRequest.pb(folders.SearchFoldersRequest()) transcode.return_value = { "method": "post", @@ -7916,6 +7979,7 @@ def test_search_folders_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = folders.SearchFoldersResponse() + post_with_metadata.return_value = folders.SearchFoldersResponse(), metadata client.search_folders( request, @@ -7927,6 +7991,7 @@ def test_search_folders_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_folder_rest_bad_request(request_type=folders.CreateFolderRequest): @@ -8080,10 +8145,13 @@ def test_create_folder_rest_interceptors(null_interceptor): ), mock.patch.object( transports.FoldersRestInterceptor, "post_create_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_create_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_create_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.CreateFolderRequest.pb(folders.CreateFolderRequest()) transcode.return_value = { "method": "post", @@ -8105,6 +8173,7 @@ def test_create_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_folder( request, @@ -8116,6 +8185,7 @@ def test_create_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_folder_rest_bad_request(request_type=folders.UpdateFolderRequest): @@ -8269,10 +8339,13 @@ def test_update_folder_rest_interceptors(null_interceptor): ), mock.patch.object( transports.FoldersRestInterceptor, "post_update_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_update_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_update_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.UpdateFolderRequest.pb(folders.UpdateFolderRequest()) transcode.return_value = { "method": "post", @@ -8294,6 +8367,7 @@ def test_update_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_folder( request, @@ -8305,6 +8379,7 @@ def test_update_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_move_folder_rest_bad_request(request_type=folders.MoveFolderRequest): @@ -8381,10 +8456,13 @@ def test_move_folder_rest_interceptors(null_interceptor): ), mock.patch.object( transports.FoldersRestInterceptor, "post_move_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_move_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_move_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.MoveFolderRequest.pb(folders.MoveFolderRequest()) transcode.return_value = { "method": "post", @@ -8406,6 +8484,7 @@ def test_move_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.move_folder( request, @@ -8417,6 +8496,7 @@ def test_move_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_folder_rest_bad_request(request_type=folders.DeleteFolderRequest): @@ -8493,10 +8573,13 @@ def test_delete_folder_rest_interceptors(null_interceptor): ), mock.patch.object( transports.FoldersRestInterceptor, "post_delete_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_delete_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_delete_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.DeleteFolderRequest.pb(folders.DeleteFolderRequest()) transcode.return_value = { "method": "post", @@ -8518,6 +8601,7 @@ def test_delete_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_folder( request, @@ -8529,6 +8613,7 @@ def test_delete_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_undelete_folder_rest_bad_request(request_type=folders.UndeleteFolderRequest): @@ -8605,10 +8690,13 @@ def test_undelete_folder_rest_interceptors(null_interceptor): ), mock.patch.object( transports.FoldersRestInterceptor, "post_undelete_folder" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_undelete_folder_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_undelete_folder" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = folders.UndeleteFolderRequest.pb(folders.UndeleteFolderRequest()) transcode.return_value = { "method": "post", @@ -8630,6 +8718,7 @@ def test_undelete_folder_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.undelete_folder( request, @@ -8641,6 +8730,7 @@ def test_undelete_folder_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_iam_policy_rest_bad_request( @@ -8722,10 +8812,13 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_get_iam_policy" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_get_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_get_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.GetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -8747,6 +8840,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.get_iam_policy( request, @@ -8758,6 +8852,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_iam_policy_rest_bad_request( @@ -8839,10 +8934,13 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_set_iam_policy" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_set_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_set_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.SetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -8864,6 +8962,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.set_iam_policy( request, @@ -8875,6 +8974,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_test_iam_permissions_rest_bad_request( @@ -8954,10 +9054,13 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.FoldersRestInterceptor, "post_test_iam_permissions" ) as post, mock.patch.object( + transports.FoldersRestInterceptor, "post_test_iam_permissions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.FoldersRestInterceptor, "pre_test_iam_permissions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.TestIamPermissionsRequest() transcode.return_value = { "method": "post", @@ -8981,6 +9084,10 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + post_with_metadata.return_value = ( + iam_policy_pb2.TestIamPermissionsResponse(), + metadata, + ) client.test_iam_permissions( request, @@ -8992,6 +9099,7 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_organizations.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_organizations.py index 18afea0f64d2..ee2e7473ff80 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_organizations.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_organizations.py @@ -67,6 +67,13 @@ ) from google.cloud.resourcemanager_v3.types import organizations +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -321,6 +328,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = OrganizationsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = OrganizationsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4289,10 +4339,13 @@ def test_get_organization_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.OrganizationsRestInterceptor, "post_get_organization" ) as post, mock.patch.object( + transports.OrganizationsRestInterceptor, "post_get_organization_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.OrganizationsRestInterceptor, "pre_get_organization" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = organizations.GetOrganizationRequest.pb( organizations.GetOrganizationRequest() ) @@ -4316,6 +4369,7 @@ def test_get_organization_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = organizations.Organization() + post_with_metadata.return_value = organizations.Organization(), metadata client.get_organization( request, @@ -4327,6 +4381,7 @@ def test_get_organization_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_organizations_rest_bad_request( @@ -4411,10 +4466,14 @@ def test_search_organizations_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.OrganizationsRestInterceptor, "post_search_organizations" ) as post, mock.patch.object( + transports.OrganizationsRestInterceptor, + "post_search_organizations_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.OrganizationsRestInterceptor, "pre_search_organizations" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = organizations.SearchOrganizationsRequest.pb( organizations.SearchOrganizationsRequest() ) @@ -4440,6 +4499,10 @@ def test_search_organizations_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = organizations.SearchOrganizationsResponse() + post_with_metadata.return_value = ( + organizations.SearchOrganizationsResponse(), + metadata, + ) client.search_organizations( request, @@ -4451,6 +4514,7 @@ def test_search_organizations_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_iam_policy_rest_bad_request( @@ -4534,10 +4598,13 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.OrganizationsRestInterceptor, "post_get_iam_policy" ) as post, mock.patch.object( + transports.OrganizationsRestInterceptor, "post_get_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.OrganizationsRestInterceptor, "pre_get_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.GetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -4559,6 +4626,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.get_iam_policy( request, @@ -4570,6 +4638,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_iam_policy_rest_bad_request( @@ -4653,10 +4722,13 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.OrganizationsRestInterceptor, "post_set_iam_policy" ) as post, mock.patch.object( + transports.OrganizationsRestInterceptor, "post_set_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.OrganizationsRestInterceptor, "pre_set_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.SetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -4678,6 +4750,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.set_iam_policy( request, @@ -4689,6 +4762,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_test_iam_permissions_rest_bad_request( @@ -4770,10 +4844,14 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.OrganizationsRestInterceptor, "post_test_iam_permissions" ) as post, mock.patch.object( + transports.OrganizationsRestInterceptor, + "post_test_iam_permissions_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.OrganizationsRestInterceptor, "pre_test_iam_permissions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.TestIamPermissionsRequest() transcode.return_value = { "method": "post", @@ -4797,6 +4875,10 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + post_with_metadata.return_value = ( + iam_policy_pb2.TestIamPermissionsResponse(), + metadata, + ) client.test_iam_permissions( request, @@ -4808,6 +4890,7 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_projects.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_projects.py index ce0a5344f899..2642100bacc6 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_projects.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_projects.py @@ -76,6 +76,13 @@ ) from google.cloud.resourcemanager_v3.types import projects +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -306,6 +313,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProjectsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProjectsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7681,10 +7731,13 @@ def test_get_project_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_get_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_get_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_get_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.GetProjectRequest.pb(projects.GetProjectRequest()) transcode.return_value = { "method": "post", @@ -7706,6 +7759,7 @@ def test_get_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = projects.Project() + post_with_metadata.return_value = projects.Project(), metadata client.get_project( request, @@ -7717,6 +7771,7 @@ def test_get_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_projects_rest_bad_request(request_type=projects.ListProjectsRequest): @@ -7797,10 +7852,13 @@ def test_list_projects_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_list_projects" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_list_projects_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_list_projects" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.ListProjectsRequest.pb(projects.ListProjectsRequest()) transcode.return_value = { "method": "post", @@ -7824,6 +7882,7 @@ def test_list_projects_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = projects.ListProjectsResponse() + post_with_metadata.return_value = projects.ListProjectsResponse(), metadata client.list_projects( request, @@ -7835,6 +7894,7 @@ def test_list_projects_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_projects_rest_bad_request(request_type=projects.SearchProjectsRequest): @@ -7915,10 +7975,13 @@ def test_search_projects_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_search_projects" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_search_projects_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_search_projects" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.SearchProjectsRequest.pb(projects.SearchProjectsRequest()) transcode.return_value = { "method": "post", @@ -7942,6 +8005,7 @@ def test_search_projects_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = projects.SearchProjectsResponse() + post_with_metadata.return_value = projects.SearchProjectsResponse(), metadata client.search_projects( request, @@ -7953,6 +8017,7 @@ def test_search_projects_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_project_rest_bad_request(request_type=projects.CreateProjectRequest): @@ -8108,10 +8173,13 @@ def test_create_project_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectsRestInterceptor, "post_create_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_create_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_create_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.CreateProjectRequest.pb(projects.CreateProjectRequest()) transcode.return_value = { "method": "post", @@ -8133,6 +8201,7 @@ def test_create_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_project( request, @@ -8144,6 +8213,7 @@ def test_create_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_project_rest_bad_request(request_type=projects.UpdateProjectRequest): @@ -8299,10 +8369,13 @@ def test_update_project_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectsRestInterceptor, "post_update_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_update_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_update_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.UpdateProjectRequest.pb(projects.UpdateProjectRequest()) transcode.return_value = { "method": "post", @@ -8324,6 +8397,7 @@ def test_update_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_project( request, @@ -8335,6 +8409,7 @@ def test_update_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_move_project_rest_bad_request(request_type=projects.MoveProjectRequest): @@ -8411,10 +8486,13 @@ def test_move_project_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectsRestInterceptor, "post_move_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_move_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_move_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.MoveProjectRequest.pb(projects.MoveProjectRequest()) transcode.return_value = { "method": "post", @@ -8436,6 +8514,7 @@ def test_move_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.move_project( request, @@ -8447,6 +8526,7 @@ def test_move_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_project_rest_bad_request(request_type=projects.DeleteProjectRequest): @@ -8523,10 +8603,13 @@ def test_delete_project_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectsRestInterceptor, "post_delete_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_delete_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_delete_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.DeleteProjectRequest.pb(projects.DeleteProjectRequest()) transcode.return_value = { "method": "post", @@ -8548,6 +8631,7 @@ def test_delete_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_project( request, @@ -8559,6 +8643,7 @@ def test_delete_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_undelete_project_rest_bad_request( @@ -8637,10 +8722,13 @@ def test_undelete_project_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectsRestInterceptor, "post_undelete_project" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_undelete_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_undelete_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = projects.UndeleteProjectRequest.pb( projects.UndeleteProjectRequest() ) @@ -8664,6 +8752,7 @@ def test_undelete_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.undelete_project( request, @@ -8675,6 +8764,7 @@ def test_undelete_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_iam_policy_rest_bad_request( @@ -8756,10 +8846,13 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_get_iam_policy" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_get_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_get_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.GetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -8781,6 +8874,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.get_iam_policy( request, @@ -8792,6 +8886,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_iam_policy_rest_bad_request( @@ -8873,10 +8968,13 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_set_iam_policy" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_set_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_set_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.SetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -8898,6 +8996,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.set_iam_policy( request, @@ -8909,6 +9008,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_test_iam_permissions_rest_bad_request( @@ -8988,10 +9088,13 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectsRestInterceptor, "post_test_iam_permissions" ) as post, mock.patch.object( + transports.ProjectsRestInterceptor, "post_test_iam_permissions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectsRestInterceptor, "pre_test_iam_permissions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.TestIamPermissionsRequest() transcode.return_value = { "method": "post", @@ -9015,6 +9118,10 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + post_with_metadata.return_value = ( + iam_policy_pb2.TestIamPermissionsResponse(), + metadata, + ) client.test_iam_permissions( request, @@ -9026,6 +9133,7 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_bindings.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_bindings.py index ebdb04a2be99..5a3ff85b1d99 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_bindings.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_bindings.py @@ -71,6 +71,13 @@ ) from google.cloud.resourcemanager_v3.types import tag_bindings +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -310,6 +317,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TagBindingsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TagBindingsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3915,10 +3965,13 @@ def test_list_tag_bindings_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagBindingsRestInterceptor, "post_list_tag_bindings" ) as post, mock.patch.object( + transports.TagBindingsRestInterceptor, "post_list_tag_bindings_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagBindingsRestInterceptor, "pre_list_tag_bindings" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_bindings.ListTagBindingsRequest.pb( tag_bindings.ListTagBindingsRequest() ) @@ -3944,6 +3997,10 @@ def test_list_tag_bindings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_bindings.ListTagBindingsResponse() + post_with_metadata.return_value = ( + tag_bindings.ListTagBindingsResponse(), + metadata, + ) client.list_tag_bindings( request, @@ -3955,6 +4012,7 @@ def test_list_tag_bindings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_tag_binding_rest_bad_request( @@ -4108,10 +4166,13 @@ def test_create_tag_binding_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagBindingsRestInterceptor, "post_create_tag_binding" ) as post, mock.patch.object( + transports.TagBindingsRestInterceptor, "post_create_tag_binding_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagBindingsRestInterceptor, "pre_create_tag_binding" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_bindings.CreateTagBindingRequest.pb( tag_bindings.CreateTagBindingRequest() ) @@ -4135,6 +4196,7 @@ def test_create_tag_binding_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_tag_binding( request, @@ -4146,6 +4208,7 @@ def test_create_tag_binding_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_tag_binding_rest_bad_request( @@ -4226,10 +4289,13 @@ def test_delete_tag_binding_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagBindingsRestInterceptor, "post_delete_tag_binding" ) as post, mock.patch.object( + transports.TagBindingsRestInterceptor, "post_delete_tag_binding_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagBindingsRestInterceptor, "pre_delete_tag_binding" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_bindings.DeleteTagBindingRequest.pb( tag_bindings.DeleteTagBindingRequest() ) @@ -4253,6 +4319,7 @@ def test_delete_tag_binding_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_tag_binding( request, @@ -4264,6 +4331,7 @@ def test_delete_tag_binding_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_effective_tags_rest_bad_request( @@ -4348,10 +4416,13 @@ def test_list_effective_tags_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagBindingsRestInterceptor, "post_list_effective_tags" ) as post, mock.patch.object( + transports.TagBindingsRestInterceptor, "post_list_effective_tags_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagBindingsRestInterceptor, "pre_list_effective_tags" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_bindings.ListEffectiveTagsRequest.pb( tag_bindings.ListEffectiveTagsRequest() ) @@ -4377,6 +4448,10 @@ def test_list_effective_tags_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_bindings.ListEffectiveTagsResponse() + post_with_metadata.return_value = ( + tag_bindings.ListEffectiveTagsResponse(), + metadata, + ) client.list_effective_tags( request, @@ -4388,6 +4463,7 @@ def test_list_effective_tags_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_holds.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_holds.py index fb079f4babac..1f42864aafba 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_holds.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_holds.py @@ -72,6 +72,13 @@ ) from google.cloud.resourcemanager_v3.types import tag_holds +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -302,6 +309,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TagHoldsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TagHoldsClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3238,10 +3288,13 @@ def test_create_tag_hold_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagHoldsRestInterceptor, "post_create_tag_hold" ) as post, mock.patch.object( + transports.TagHoldsRestInterceptor, "post_create_tag_hold_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagHoldsRestInterceptor, "pre_create_tag_hold" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_holds.CreateTagHoldRequest.pb(tag_holds.CreateTagHoldRequest()) transcode.return_value = { "method": "post", @@ -3263,6 +3316,7 @@ def test_create_tag_hold_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_tag_hold( request, @@ -3274,6 +3328,7 @@ def test_create_tag_hold_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_tag_hold_rest_bad_request(request_type=tag_holds.DeleteTagHoldRequest): @@ -3350,10 +3405,13 @@ def test_delete_tag_hold_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagHoldsRestInterceptor, "post_delete_tag_hold" ) as post, mock.patch.object( + transports.TagHoldsRestInterceptor, "post_delete_tag_hold_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagHoldsRestInterceptor, "pre_delete_tag_hold" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_holds.DeleteTagHoldRequest.pb(tag_holds.DeleteTagHoldRequest()) transcode.return_value = { "method": "post", @@ -3375,6 +3433,7 @@ def test_delete_tag_hold_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_tag_hold( request, @@ -3386,6 +3445,7 @@ def test_delete_tag_hold_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_tag_holds_rest_bad_request(request_type=tag_holds.ListTagHoldsRequest): @@ -3466,10 +3526,13 @@ def test_list_tag_holds_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagHoldsRestInterceptor, "post_list_tag_holds" ) as post, mock.patch.object( + transports.TagHoldsRestInterceptor, "post_list_tag_holds_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagHoldsRestInterceptor, "pre_list_tag_holds" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_holds.ListTagHoldsRequest.pb(tag_holds.ListTagHoldsRequest()) transcode.return_value = { "method": "post", @@ -3493,6 +3556,7 @@ def test_list_tag_holds_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_holds.ListTagHoldsResponse() + post_with_metadata.return_value = tag_holds.ListTagHoldsResponse(), metadata client.list_tag_holds( request, @@ -3504,6 +3568,7 @@ def test_list_tag_holds_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_keys.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_keys.py index a80ef3dd50af..0b1279b2c21f 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_keys.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_keys.py @@ -76,6 +76,13 @@ ) from google.cloud.resourcemanager_v3.types import tag_keys +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -299,6 +306,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TagKeysClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TagKeysClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6454,10 +6504,13 @@ def test_list_tag_keys_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_list_tag_keys" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_list_tag_keys_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_list_tag_keys" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.ListTagKeysRequest.pb(tag_keys.ListTagKeysRequest()) transcode.return_value = { "method": "post", @@ -6481,6 +6534,7 @@ def test_list_tag_keys_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_keys.ListTagKeysResponse() + post_with_metadata.return_value = tag_keys.ListTagKeysResponse(), metadata client.list_tag_keys( request, @@ -6492,6 +6546,7 @@ def test_list_tag_keys_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_tag_key_rest_bad_request(request_type=tag_keys.GetTagKeyRequest): @@ -6584,10 +6639,13 @@ def test_get_tag_key_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_get_tag_key" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_get_tag_key_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_get_tag_key" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.GetTagKeyRequest.pb(tag_keys.GetTagKeyRequest()) transcode.return_value = { "method": "post", @@ -6609,6 +6667,7 @@ def test_get_tag_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_keys.TagKey() + post_with_metadata.return_value = tag_keys.TagKey(), metadata client.get_tag_key( request, @@ -6620,6 +6679,7 @@ def test_get_tag_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_namespaced_tag_key_rest_bad_request( @@ -6714,10 +6774,13 @@ def test_get_namespaced_tag_key_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_get_namespaced_tag_key" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_get_namespaced_tag_key_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_get_namespaced_tag_key" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.GetNamespacedTagKeyRequest.pb( tag_keys.GetNamespacedTagKeyRequest() ) @@ -6741,6 +6804,7 @@ def test_get_namespaced_tag_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_keys.TagKey() + post_with_metadata.return_value = tag_keys.TagKey(), metadata client.get_namespaced_tag_key( request, @@ -6752,6 +6816,7 @@ def test_get_namespaced_tag_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_tag_key_rest_bad_request(request_type=tag_keys.CreateTagKeyRequest): @@ -6907,10 +6972,13 @@ def test_create_tag_key_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagKeysRestInterceptor, "post_create_tag_key" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_create_tag_key_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_create_tag_key" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.CreateTagKeyRequest.pb(tag_keys.CreateTagKeyRequest()) transcode.return_value = { "method": "post", @@ -6932,6 +7000,7 @@ def test_create_tag_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_tag_key( request, @@ -6943,6 +7012,7 @@ def test_create_tag_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_tag_key_rest_bad_request(request_type=tag_keys.UpdateTagKeyRequest): @@ -7098,10 +7168,13 @@ def test_update_tag_key_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagKeysRestInterceptor, "post_update_tag_key" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_update_tag_key_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_update_tag_key" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.UpdateTagKeyRequest.pb(tag_keys.UpdateTagKeyRequest()) transcode.return_value = { "method": "post", @@ -7123,6 +7196,7 @@ def test_update_tag_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_tag_key( request, @@ -7134,6 +7208,7 @@ def test_update_tag_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_tag_key_rest_bad_request(request_type=tag_keys.DeleteTagKeyRequest): @@ -7210,10 +7285,13 @@ def test_delete_tag_key_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagKeysRestInterceptor, "post_delete_tag_key" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_delete_tag_key_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_delete_tag_key" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_keys.DeleteTagKeyRequest.pb(tag_keys.DeleteTagKeyRequest()) transcode.return_value = { "method": "post", @@ -7235,6 +7313,7 @@ def test_delete_tag_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_tag_key( request, @@ -7246,6 +7325,7 @@ def test_delete_tag_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_iam_policy_rest_bad_request( @@ -7327,10 +7407,13 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_get_iam_policy" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_get_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_get_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.GetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -7352,6 +7435,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.get_iam_policy( request, @@ -7363,6 +7447,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_iam_policy_rest_bad_request( @@ -7444,10 +7529,13 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_set_iam_policy" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_set_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_set_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.SetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -7469,6 +7557,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.set_iam_policy( request, @@ -7480,6 +7569,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_test_iam_permissions_rest_bad_request( @@ -7559,10 +7649,13 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagKeysRestInterceptor, "post_test_iam_permissions" ) as post, mock.patch.object( + transports.TagKeysRestInterceptor, "post_test_iam_permissions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagKeysRestInterceptor, "pre_test_iam_permissions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.TestIamPermissionsRequest() transcode.return_value = { "method": "post", @@ -7586,6 +7679,10 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + post_with_metadata.return_value = ( + iam_policy_pb2.TestIamPermissionsResponse(), + metadata, + ) client.test_iam_permissions( request, @@ -7597,6 +7694,7 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_values.py b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_values.py index bc47dde37a98..b296aeab0234 100644 --- a/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_values.py +++ b/packages/google-cloud-resource-manager/tests/unit/gapic/resourcemanager_v3/test_tag_values.py @@ -76,6 +76,13 @@ ) from google.cloud.resourcemanager_v3.types import tag_values +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -309,6 +316,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = TagValuesClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = TagValuesClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6493,10 +6543,13 @@ def test_list_tag_values_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_list_tag_values" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_list_tag_values_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_list_tag_values" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.ListTagValuesRequest.pb( tag_values.ListTagValuesRequest() ) @@ -6522,6 +6575,7 @@ def test_list_tag_values_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_values.ListTagValuesResponse() + post_with_metadata.return_value = tag_values.ListTagValuesResponse(), metadata client.list_tag_values( request, @@ -6533,6 +6587,7 @@ def test_list_tag_values_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_tag_value_rest_bad_request(request_type=tag_values.GetTagValueRequest): @@ -6623,10 +6678,13 @@ def test_get_tag_value_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_get_tag_value" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_get_tag_value_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_get_tag_value" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.GetTagValueRequest.pb(tag_values.GetTagValueRequest()) transcode.return_value = { "method": "post", @@ -6648,6 +6706,7 @@ def test_get_tag_value_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_values.TagValue() + post_with_metadata.return_value = tag_values.TagValue(), metadata client.get_tag_value( request, @@ -6659,6 +6718,7 @@ def test_get_tag_value_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_namespaced_tag_value_rest_bad_request( @@ -6751,10 +6811,14 @@ def test_get_namespaced_tag_value_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_get_namespaced_tag_value" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, + "post_get_namespaced_tag_value_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_get_namespaced_tag_value" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.GetNamespacedTagValueRequest.pb( tag_values.GetNamespacedTagValueRequest() ) @@ -6778,6 +6842,7 @@ def test_get_namespaced_tag_value_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = tag_values.TagValue() + post_with_metadata.return_value = tag_values.TagValue(), metadata client.get_namespaced_tag_value( request, @@ -6789,6 +6854,7 @@ def test_get_namespaced_tag_value_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_tag_value_rest_bad_request( @@ -6944,10 +7010,13 @@ def test_create_tag_value_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagValuesRestInterceptor, "post_create_tag_value" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_create_tag_value_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_create_tag_value" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.CreateTagValueRequest.pb( tag_values.CreateTagValueRequest() ) @@ -6971,6 +7040,7 @@ def test_create_tag_value_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_tag_value( request, @@ -6982,6 +7052,7 @@ def test_create_tag_value_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_tag_value_rest_bad_request( @@ -7137,10 +7208,13 @@ def test_update_tag_value_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagValuesRestInterceptor, "post_update_tag_value" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_update_tag_value_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_update_tag_value" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.UpdateTagValueRequest.pb( tag_values.UpdateTagValueRequest() ) @@ -7164,6 +7238,7 @@ def test_update_tag_value_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_tag_value( request, @@ -7175,6 +7250,7 @@ def test_update_tag_value_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_tag_value_rest_bad_request( @@ -7253,10 +7329,13 @@ def test_delete_tag_value_rest_interceptors(null_interceptor): ), mock.patch.object( transports.TagValuesRestInterceptor, "post_delete_tag_value" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_delete_tag_value_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_delete_tag_value" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = tag_values.DeleteTagValueRequest.pb( tag_values.DeleteTagValueRequest() ) @@ -7280,6 +7359,7 @@ def test_delete_tag_value_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_tag_value( request, @@ -7291,6 +7371,7 @@ def test_delete_tag_value_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_iam_policy_rest_bad_request( @@ -7372,10 +7453,13 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_get_iam_policy" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_get_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_get_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.GetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -7397,6 +7481,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.get_iam_policy( request, @@ -7408,6 +7493,7 @@ def test_get_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_iam_policy_rest_bad_request( @@ -7489,10 +7575,13 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_set_iam_policy" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_set_iam_policy_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_set_iam_policy" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.SetIamPolicyRequest() transcode.return_value = { "method": "post", @@ -7514,6 +7603,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = policy_pb2.Policy() + post_with_metadata.return_value = policy_pb2.Policy(), metadata client.set_iam_policy( request, @@ -7525,6 +7615,7 @@ def test_set_iam_policy_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_test_iam_permissions_rest_bad_request( @@ -7604,10 +7695,13 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.TagValuesRestInterceptor, "post_test_iam_permissions" ) as post, mock.patch.object( + transports.TagValuesRestInterceptor, "post_test_iam_permissions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.TagValuesRestInterceptor, "pre_test_iam_permissions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = iam_policy_pb2.TestIamPermissionsRequest() transcode.return_value = { "method": "post", @@ -7631,6 +7725,10 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = iam_policy_pb2.TestIamPermissionsResponse() + post_with_metadata.return_value = ( + iam_policy_pb2.TestIamPermissionsResponse(), + metadata, + ) client.test_iam_permissions( request, @@ -7642,6 +7740,7 @@ def test_test_iam_permissions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-run/README.rst b/packages/google-cloud-run/README.rst index 2faead2dd549..09fdb6e57db6 100644 --- a/packages/google-cloud-run/README.rst +++ b/packages/google-cloud-run/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Run.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Run.: https://cloud.google.com/run/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-run/google/cloud/run/gapic_version.py b/packages/google-cloud-run/google/cloud/run/gapic_version.py index 7008b740153b..558c8aab67c5 100644 --- a/packages/google-cloud-run/google/cloud/run/gapic_version.py +++ b/packages/google-cloud-run/google/cloud/run/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.10.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py b/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py index 7008b740153b..558c8aab67c5 100644 --- a/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py +++ b/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.10.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-run/noxfile.py b/packages/google-cloud-run/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-run/noxfile.py +++ b/packages/google-cloud-run/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json b/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json index 564a70dc7866..91a10655bff1 100644 --- a/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json +++ b/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-run", - "version": "0.10.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-run/setup.py b/packages/google-cloud-run/setup.py index a110b1cbca4b..659aa7537c14 100644 --- a/packages/google-cloud-run/setup.py +++ b/packages/google-cloud-run/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-run" diff --git a/packages/google-cloud-run/testing/constraints-3.7.txt b/packages/google-cloud-run/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-run/testing/constraints-3.7.txt +++ b/packages/google-cloud-run/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-secret-manager/README.rst b/packages/google-cloud-secret-manager/README.rst index 40a0e912bad0..55716fd5a20b 100644 --- a/packages/google-cloud-secret-manager/README.rst +++ b/packages/google-cloud-secret-manager/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Secret Manager.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Secret Manager.: https://cloud.google.com/secret-manager/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py index 411b87d337df..558c8aab67c5 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py index 411b87d337df..558c8aab67c5 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py index 411b87d337df..558c8aab67c5 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py index 411b87d337df..558c8aab67c5 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.23.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/noxfile.py b/packages/google-cloud-secret-manager/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-secret-manager/noxfile.py +++ b/packages/google-cloud-secret-manager/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json index 5850fce1d713..e75ffe273c93 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secret-manager", - "version": "2.23.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json index 0a11bae7aef9..f2d2a2eaea8e 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secretmanager", - "version": "2.23.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json index 692df783d6a4..cdba6a34a0ba 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secretmanager", - "version": "2.23.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/setup.py b/packages/google-cloud-secret-manager/setup.py index 65f3dc2826a5..fcd0dabdd209 100644 --- a/packages/google-cloud-secret-manager/setup.py +++ b/packages/google-cloud-secret-manager/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-secret-manager" diff --git a/packages/google-cloud-secret-manager/testing/constraints-3.7.txt b/packages/google-cloud-secret-manager/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-secret-manager/testing/constraints-3.7.txt +++ b/packages/google-cloud-secret-manager/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-securesourcemanager/README.rst b/packages/google-cloud-securesourcemanager/README.rst index 7fa094107a63..a0e17518a3b0 100644 --- a/packages/google-cloud-securesourcemanager/README.rst +++ b/packages/google-cloud-securesourcemanager/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Secure Source Manager API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Secure Source Manager API.: https://cloud.google.com/secure-source-manager/docs/overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py index 7daf9a1dd221..558c8aab67c5 100644 --- a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py +++ b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py index 7daf9a1dd221..558c8aab67c5 100644 --- a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py +++ b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securesourcemanager/noxfile.py b/packages/google-cloud-securesourcemanager/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-securesourcemanager/noxfile.py +++ b/packages/google-cloud-securesourcemanager/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json b/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json index 965aa493cde5..61b28fdc2e03 100644 --- a/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json +++ b/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securesourcemanager", - "version": "0.1.13" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securesourcemanager/setup.py b/packages/google-cloud-securesourcemanager/setup.py index 79ffdc683040..0454983f07ba 100644 --- a/packages/google-cloud-securesourcemanager/setup.py +++ b/packages/google-cloud-securesourcemanager/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securesourcemanager" diff --git a/packages/google-cloud-securesourcemanager/testing/constraints-3.7.txt b/packages/google-cloud-securesourcemanager/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-securesourcemanager/testing/constraints-3.7.txt +++ b/packages/google-cloud-securesourcemanager/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-securitycenter/README.rst b/packages/google-cloud-securitycenter/README.rst index af0c588c2fcc..947f0ced471e 100644 --- a/packages/google-cloud-securitycenter/README.rst +++ b/packages/google-cloud-securitycenter/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Security Command Center.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Security Command Center.: https://cloud.google.com/security-command-center -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py index 3026e41db675..558c8aab67c5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.37.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py index 3026e41db675..558c8aab67c5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.37.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py index 3026e41db675..558c8aab67c5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.37.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py index 3026e41db675..558c8aab67c5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.37.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py index 3026e41db675..558c8aab67c5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.37.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/noxfile.py b/packages/google-cloud-securitycenter/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-securitycenter/noxfile.py +++ b/packages/google-cloud-securitycenter/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json index 44c212ec6ce8..efb11fe5de6c 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "1.37.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json index 974d02cb150b..dc6a6d6dd78d 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "1.37.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json index 9ec27e16b8f1..7eed8e8dc8ab 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "1.37.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json index 8a3b13727fb0..e176e0b8c043 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "1.37.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/setup.py b/packages/google-cloud-securitycenter/setup.py index d6fdc50d0cc5..8ca5dbb9b581 100644 --- a/packages/google-cloud-securitycenter/setup.py +++ b/packages/google-cloud-securitycenter/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycenter" diff --git a/packages/google-cloud-securitycenter/testing/constraints-3.7.txt b/packages/google-cloud-securitycenter/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-securitycenter/testing/constraints-3.7.txt +++ b/packages/google-cloud-securitycenter/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-securitycentermanagement/README.rst b/packages/google-cloud-securitycentermanagement/README.rst index 75b9aba90be0..46715c0c6133 100644 --- a/packages/google-cloud-securitycentermanagement/README.rst +++ b/packages/google-cloud-securitycentermanagement/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Security Center Management API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Security Center Management API.: https://cloud.google.com/securitycentermanagement/docs/overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py index ba2789011e90..558c8aab67c5 100644 --- a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py +++ b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.19" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py index ba2789011e90..558c8aab67c5 100644 --- a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py +++ b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.19" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycentermanagement/noxfile.py b/packages/google-cloud-securitycentermanagement/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-securitycentermanagement/noxfile.py +++ b/packages/google-cloud-securitycentermanagement/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json b/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json index 82bc77853286..aa268d46e53c 100644 --- a/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json +++ b/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycentermanagement", - "version": "0.1.19" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycentermanagement/setup.py b/packages/google-cloud-securitycentermanagement/setup.py index a372229d21c9..bf9c042e91de 100644 --- a/packages/google-cloud-securitycentermanagement/setup.py +++ b/packages/google-cloud-securitycentermanagement/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycentermanagement" diff --git a/packages/google-cloud-securitycentermanagement/testing/constraints-3.7.txt b/packages/google-cloud-securitycentermanagement/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-securitycentermanagement/testing/constraints-3.7.txt +++ b/packages/google-cloud-securitycentermanagement/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-service-directory/README.rst b/packages/google-cloud-service-directory/README.rst index a3010fc55232..4e86c8d7b750 100644 --- a/packages/google-cloud-service-directory/README.rst +++ b/packages/google-cloud-service-directory/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Service Directory.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Service Directory.: https://cloud.google.com/service-directory/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py index 2159c8af6f8e..558c8aab67c5 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.14.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/noxfile.py b/packages/google-cloud-service-directory/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-service-directory/noxfile.py +++ b/packages/google-cloud-service-directory/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json index 26b66b5127a5..bb916a8e137a 100644 --- a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json +++ b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-directory", - "version": "1.14.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json index 9d08342b3bdc..bbc7749e9905 100644 --- a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json +++ b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-directory", - "version": "1.14.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-service-directory/setup.py b/packages/google-cloud-service-directory/setup.py index 38c563e3f54b..397e68b0b7ba 100644 --- a/packages/google-cloud-service-directory/setup.py +++ b/packages/google-cloud-service-directory/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-directory" diff --git a/packages/google-cloud-service-directory/testing/constraints-3.7.txt b/packages/google-cloud-service-directory/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-service-directory/testing/constraints-3.7.txt +++ b/packages/google-cloud-service-directory/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-service-management/README.rst b/packages/google-cloud-service-management/README.rst index fb364280c9c1..7fea5f070a99 100644 --- a/packages/google-cloud-service-management/README.rst +++ b/packages/google-cloud-service-management/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Service Management.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Service Management.: https://cloud.google.com/service-infrastructure/docs/overview/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py b/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py +++ b/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py b/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py +++ b/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-service-management/noxfile.py b/packages/google-cloud-service-management/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-service-management/noxfile.py +++ b/packages/google-cloud-service-management/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json b/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json index e804c8c73812..fb37827cecec 100644 --- a/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json +++ b/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-management", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-service-management/setup.py b/packages/google-cloud-service-management/setup.py index 163edfbbd2b4..eb917ce9f7c5 100644 --- a/packages/google-cloud-service-management/setup.py +++ b/packages/google-cloud-service-management/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-management" diff --git a/packages/google-cloud-service-management/testing/constraints-3.7.txt b/packages/google-cloud-service-management/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-service-management/testing/constraints-3.7.txt +++ b/packages/google-cloud-service-management/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-service-management/tests/unit/gapic/servicemanagement_v1/test_service_manager.py b/packages/google-cloud-service-management/tests/unit/gapic/servicemanagement_v1/test_service_manager.py index f90a335534cc..8fc2f71c2ccc 100644 --- a/packages/google-cloud-service-management/tests/unit/gapic/servicemanagement_v1/test_service_manager.py +++ b/packages/google-cloud-service-management/tests/unit/gapic/servicemanagement_v1/test_service_manager.py @@ -10787,6 +10787,7 @@ def test_create_service_config_rest_call_success(request_type): "experimental_features": { "rest_async_io_enabled": True, "protobuf_pythonic_types_enabled": True, + "unversioned_package_disabled": True, }, }, "node_settings": {"common": {}}, diff --git a/packages/google-cloud-tasks/README.rst b/packages/google-cloud-tasks/README.rst index c104f1d386df..ee8c1e6b3cdf 100644 --- a/packages/google-cloud-tasks/README.rst +++ b/packages/google-cloud-tasks/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Tasks.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Tasks.: https://cloud.google.com/tasks/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py index 4ed6d7530c12..558c8aab67c5 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py index 4ed6d7530c12..558c8aab67c5 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py index 4ed6d7530c12..558c8aab67c5 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py index 4ed6d7530c12..558c8aab67c5 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/noxfile.py b/packages/google-cloud-tasks/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-tasks/noxfile.py +++ b/packages/google-cloud-tasks/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json index 657f83e1c1d0..a40f846fdcce 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "2.19.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json index 8d6c089251da..2b3fcc2324d1 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "2.19.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json index 74cdfab33943..c3812fadd698 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "2.19.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/setup.py b/packages/google-cloud-tasks/setup.py index 6b238b4edf74..9e5d18b88912 100644 --- a/packages/google-cloud-tasks/setup.py +++ b/packages/google-cloud-tasks/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-tasks" diff --git a/packages/google-cloud-tasks/testing/constraints-3.7.txt b/packages/google-cloud-tasks/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-tasks/testing/constraints-3.7.txt +++ b/packages/google-cloud-tasks/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-translate/README.rst b/packages/google-cloud-translate/README.rst index c8a652c6289e..51cc8497ca60 100644 --- a/packages/google-cloud-translate/README.rst +++ b/packages/google-cloud-translate/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Translation.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Translation.: https://cloud.google.com/translate/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-translate/google/cloud/translate/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate/gapic_version.py index c3ababdf3b1a..558c8aab67c5 100644 --- a/packages/google-cloud-translate/google/cloud/translate/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py index c3ababdf3b1a..558c8aab67c5 100644 --- a/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py index c3ababdf3b1a..558c8aab67c5 100644 --- a/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.20.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-translate/noxfile.py b/packages/google-cloud-translate/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-translate/noxfile.py +++ b/packages/google-cloud-translate/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json index d8f81b5c92f2..de406536e428 100644 --- a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json +++ b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-translate", - "version": "3.20.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json index 295b93fbc1db..74f2e4c9def9 100644 --- a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json +++ b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-translate", - "version": "3.20.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-translate/setup.py b/packages/google-cloud-translate/setup.py index 6b316e21b7a0..367fda9a8894 100644 --- a/packages/google-cloud-translate/setup.py +++ b/packages/google-cloud-translate/setup.py @@ -47,7 +47,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-translate" diff --git a/packages/google-cloud-translate/testing/constraints-3.7.txt b/packages/google-cloud-translate/testing/constraints-3.7.txt index 6ef964d6f0d7..557202a78088 100644 --- a/packages/google-cloud-translate/testing/constraints-3.7.txt +++ b/packages/google-cloud-translate/testing/constraints-3.7.txt @@ -9,4 +9,4 @@ google-auth==2.14.1 proto-plus==1.22.3 google-cloud-core==1.4.4 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-visionai/README.rst b/packages/google-cloud-visionai/README.rst index 50d8bde3dd97..1ad00d55d4fd 100644 --- a/packages/google-cloud-visionai/README.rst +++ b/packages/google-cloud-visionai/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Vision AI API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Vision AI API.: https://cloud.google.com/vision-ai/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py index cf5493b86bbc..558c8aab67c5 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.7" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/noxfile.py b/packages/google-cloud-visionai/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-visionai/noxfile.py +++ b/packages/google-cloud-visionai/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json index 591c6f900c16..55144efe90c6 100644 --- a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json +++ b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-visionai", - "version": "0.1.7" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json index e1e9280c3fa8..11704c120259 100644 --- a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json +++ b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-visionai", - "version": "0.1.7" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-visionai/setup.py b/packages/google-cloud-visionai/setup.py index 42d46fd11a71..1486c4a2c695 100644 --- a/packages/google-cloud-visionai/setup.py +++ b/packages/google-cloud-visionai/setup.py @@ -46,7 +46,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-visionai" diff --git a/packages/google-cloud-visionai/testing/constraints-3.7.txt b/packages/google-cloud-visionai/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-visionai/testing/constraints-3.7.txt +++ b/packages/google-cloud-visionai/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 From 7fb3f49a1531b4da24771c4ce8380be98980fe8b Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:51:22 +0500 Subject: [PATCH 05/13] feat: [google-cloud-securitycenter] added more information about DDoS attack in cloud armor proto (#13527) BEGIN_COMMIT_OVERRIDE feat: added more information about DDoS attack in cloud armor proto feat: added data access event fields to finding proto docs: Clarified comments for tag_values field in resource_value_config to make it clear that field represents tag value ids, not tag values END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. feat: added data access event fields to finding proto docs: Clarified comments for tag_values field in resource_value_config to make it clear that field represents tag value ids, not tag values PiperOrigin-RevId: 726529258 Source-Link: https://github.com/googleapis/googleapis/commit/f2ce5f2be39bdedbc0b576812873f521230bf3d7 Source-Link: https://github.com/googleapis/googleapis-gen/commit/853c69d04566f49c4170c3c5b6b5ed3f3075c494 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5Y2VudGVyLy5Pd2xCb3QueWFtbCIsImgiOiI4NTNjNjlkMDQ1NjZmNDljNDE3MGMzYzViNmI1ZWQzZjMwNzVjNDk0In0= --------- Co-authored-by: Owl Bot --- .../cloud/securitycenter_v2/__init__.py | 8 ++ .../services/security_center/async_client.py | 4 + .../services/security_center/client.py | 4 + .../security_center/transports/rest_base.py | 8 ++ .../cloud/securitycenter_v2/types/__init__.py | 8 ++ .../securitycenter_v2/types/cloud_armor.py | 26 +++-- .../types/data_access_event.py | 88 +++++++++++++++ .../types/data_flow_event.py | 96 +++++++++++++++++ .../types/data_retention_deletion_event.py | 100 ++++++++++++++++++ .../cloud/securitycenter_v2/types/disk.py | 46 ++++++++ .../cloud/securitycenter_v2/types/finding.py | 44 ++++++++ .../securitycenter_v2/types/mitre_attack.py | 7 +- .../securitycenter_v2/types/org_policy.py | 2 +- .../cloud/securitycenter_v2/types/resource.py | 34 ++++++ .../types/resource_value_config.py | 5 +- .../securitycenter_v2/types/vulnerability.py | 7 ++ .../securitycenter_v2/test_security_center.py | 66 +++++++++++- 17 files changed, 541 insertions(+), 12 deletions(-) create mode 100644 packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_access_event.py create mode 100644 packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_flow_event.py create mode 100644 packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_retention_deletion_event.py create mode 100644 packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/disk.py diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/__init__.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/__init__.py index 10e9a22fcd18..149d59483ba1 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/__init__.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/__init__.py @@ -38,7 +38,11 @@ from .types.connection import Connection from .types.contact_details import Contact, ContactDetails from .types.container import Container +from .types.data_access_event import DataAccessEvent +from .types.data_flow_event import DataFlowEvent +from .types.data_retention_deletion_event import DataRetentionDeletionEvent from .types.database import Database +from .types.disk import Disk from .types.exfiltration import ExfilResource, Exfiltration from .types.external_system import ExternalSystem from .types.file import File @@ -169,11 +173,15 @@ "CreateSourceRequest", "Cve", "Cvssv3", + "DataAccessEvent", + "DataFlowEvent", + "DataRetentionDeletionEvent", "Database", "DeleteBigQueryExportRequest", "DeleteMuteConfigRequest", "DeleteNotificationConfigRequest", "DeleteResourceValueConfigRequest", + "Disk", "EnvironmentVariable", "ExfilResource", "Exfiltration", diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/async_client.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/async_client.py index 1b47ed36d4c8..9c2484b05ffb 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/async_client.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/async_client.py @@ -66,7 +66,11 @@ compliance, connection, container, + data_access_event, + data_flow_event, + data_retention_deletion_event, database, + disk, exfiltration, ) from google.cloud.securitycenter_v2.types import ( diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/client.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/client.py index 8e4cb83bd6ec..511cf32cbedb 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/client.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/client.py @@ -83,7 +83,11 @@ compliance, connection, container, + data_access_event, + data_flow_event, + data_retention_deletion_event, database, + disk, exfiltration, ) from google.cloud.securitycenter_v2.types import ( diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/transports/rest_base.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/transports/rest_base.py index 70ea3d116a06..ce64f5836466 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/transports/rest_base.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/services/security_center/transports/rest_base.py @@ -1373,6 +1373,10 @@ def _get_http_options(): "method": "get", "uri": "/v2/{parent=organizations/*/simulations/*}/attackPaths", }, + { + "method": "get", + "uri": "/v2/{parent=organizations/*}/attackPaths", + }, { "method": "get", "uri": "/v2/{parent=organizations/*/simulations/*/valuedResources/*}/attackPaths", @@ -1794,6 +1798,10 @@ def _get_http_options(): "method": "get", "uri": "/v2/{parent=organizations/*/simulations/*/attackExposureResults/*}/valuedResources", }, + { + "method": "get", + "uri": "/v2/{parent=organizations/*}/valuedResources", + }, ] return http_options diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/__init__.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/__init__.py index a091eb96721b..d476930d76c3 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/__init__.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/__init__.py @@ -32,7 +32,11 @@ from .connection import Connection from .contact_details import Contact, ContactDetails from .container import Container +from .data_access_event import DataAccessEvent +from .data_flow_event import DataFlowEvent +from .data_retention_deletion_event import DataRetentionDeletionEvent from .database import Database +from .disk import Disk from .exfiltration import ExfilResource, Exfiltration from .external_system import ExternalSystem from .file import File @@ -150,7 +154,11 @@ "Contact", "ContactDetails", "Container", + "DataAccessEvent", + "DataFlowEvent", + "DataRetentionDeletionEvent", "Database", + "Disk", "ExfilResource", "Exfiltration", "ExternalSystem", diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/cloud_armor.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/cloud_armor.py index 7a208bf9c56f..81ad87b63d70 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/cloud_armor.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/cloud_armor.py @@ -187,17 +187,35 @@ class Attack(proto.Message): r"""Information about DDoS attack volume and classification. Attributes: - volume_pps (int): + volume_pps_long (int): Total PPS (packets per second) volume of attack. - volume_bps (int): + volume_bps_long (int): Total BPS (bytes per second) volume of attack. classification (str): Type of attack, for example, 'SYN-flood', 'NTP-udp', or 'CHARGEN-udp'. + volume_pps (int): + Total PPS (packets per second) volume of attack. Deprecated + - refer to volume_pps_long instead. + volume_bps (int): + Total BPS (bytes per second) volume of attack. Deprecated - + refer to volume_bps_long instead. """ + volume_pps_long: int = proto.Field( + proto.INT64, + number=4, + ) + volume_bps_long: int = proto.Field( + proto.INT64, + number=5, + ) + classification: str = proto.Field( + proto.STRING, + number=3, + ) volume_pps: int = proto.Field( proto.INT32, number=1, @@ -206,10 +224,6 @@ class Attack(proto.Message): proto.INT32, number=2, ) - classification: str = proto.Field( - proto.STRING, - number=3, - ) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_access_event.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_access_event.py new file mode 100644 index 000000000000..0e07e1a2d8cc --- /dev/null +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_access_event.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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. +# +from __future__ import annotations + +from typing import MutableMapping, MutableSequence + +from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.securitycenter.v2", + manifest={ + "DataAccessEvent", + }, +) + + +class DataAccessEvent(proto.Message): + r"""Details about a data access attempt made by a principal not + authorized under applicable data security policy. + + Attributes: + event_id (str): + Unique identifier for data access event. + principal_email (str): + The email address of the principal that + accessed the data. The principal could be a user + account, service account, Google group, or + other. + operation (google.cloud.securitycenter_v2.types.DataAccessEvent.Operation): + The operation performed by the principal to + access the data. + event_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp of data access event. + """ + + class Operation(proto.Enum): + r"""The operation of a data access event. + + Values: + OPERATION_UNSPECIFIED (0): + The operation is unspecified. + READ (1): + Represents a read operation. + MOVE (2): + Represents a move operation. + COPY (3): + Represents a copy operation. + """ + OPERATION_UNSPECIFIED = 0 + READ = 1 + MOVE = 2 + COPY = 3 + + event_id: str = proto.Field( + proto.STRING, + number=1, + ) + principal_email: str = proto.Field( + proto.STRING, + number=2, + ) + operation: Operation = proto.Field( + proto.ENUM, + number=3, + enum=Operation, + ) + event_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=4, + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_flow_event.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_flow_event.py new file mode 100644 index 000000000000..138118b576e9 --- /dev/null +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_flow_event.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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. +# +from __future__ import annotations + +from typing import MutableMapping, MutableSequence + +from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.securitycenter.v2", + manifest={ + "DataFlowEvent", + }, +) + + +class DataFlowEvent(proto.Message): + r"""Details about a data flow event, in which either the data is + moved to or is accessed from a non-compliant geo-location, as + defined in the applicable data security policy. + + Attributes: + event_id (str): + Unique identifier for data flow event. + principal_email (str): + The email address of the principal that + initiated the data flow event. The principal + could be a user account, service account, Google + group, or other. + operation (google.cloud.securitycenter_v2.types.DataFlowEvent.Operation): + The operation performed by the principal for + the data flow event. + violated_location (str): + Non-compliant location of the principal or + the data destination. + event_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp of data flow event. + """ + + class Operation(proto.Enum): + r"""The operation of a data flow event. + + Values: + OPERATION_UNSPECIFIED (0): + The operation is unspecified. + READ (1): + Represents a read operation. + MOVE (2): + Represents a move operation. + COPY (3): + Represents a copy operation. + """ + OPERATION_UNSPECIFIED = 0 + READ = 1 + MOVE = 2 + COPY = 3 + + event_id: str = proto.Field( + proto.STRING, + number=1, + ) + principal_email: str = proto.Field( + proto.STRING, + number=2, + ) + operation: Operation = proto.Field( + proto.ENUM, + number=3, + enum=Operation, + ) + violated_location: str = proto.Field( + proto.STRING, + number=4, + ) + event_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=5, + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_retention_deletion_event.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_retention_deletion_event.py new file mode 100644 index 000000000000..9fced00f67ab --- /dev/null +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/data_retention_deletion_event.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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. +# +from __future__ import annotations + +from typing import MutableMapping, MutableSequence + +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.securitycenter.v2", + manifest={ + "DataRetentionDeletionEvent", + }, +) + + +class DataRetentionDeletionEvent(proto.Message): + r"""Details about data retention deletion violations, in which + the data is non-compliant based on their retention or deletion + time, as defined in the applicable data security policy. The + Data Retention Deletion (DRD) control is a control of the DSPM + (Data Security Posture Management) suite that enables + organizations to manage data retention and deletion policies in + compliance with regulations, such as GDPR and CRPA. DRD supports + two primary policy types: maximum storage length (max TTL) and + minimum storage length (min TTL). Both are aimed at helping + organizations meet regulatory and data management commitments. + + Attributes: + event_detection_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp indicating when the event was + detected. + data_object_count (int): + Number of objects that violated the policy + for this resource. If the number is less than + 1,000, then the value of this field is the exact + number. If the number of objects that violated + the policy is greater than or equal to 1,000, + then the value of this field is 1000. + max_retention_allowed (google.protobuf.duration_pb2.Duration): + Maximum duration of retention allowed from the DRD control. + This comes from the DRD control where users set a max TTL + for their data. For example, suppose that a user sets the + max TTL for a Cloud Storage bucket to 90 days. However, an + object in that bucket is 100 days old. In this case, a + DataRetentionDeletionEvent will be generated for that Cloud + Storage bucket, and the max_retention_allowed is 90 days. + event_type (google.cloud.securitycenter_v2.types.DataRetentionDeletionEvent.EventType): + Type of the DRD event. + """ + + class EventType(proto.Enum): + r"""Type of the DRD event. + + Values: + EVENT_TYPE_UNSPECIFIED (0): + Unspecified event type. + EVENT_TYPE_MAX_TTL_EXCEEDED (1): + The maximum retention time has been exceeded. + """ + EVENT_TYPE_UNSPECIFIED = 0 + EVENT_TYPE_MAX_TTL_EXCEEDED = 1 + + event_detection_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + data_object_count: int = proto.Field( + proto.INT64, + number=3, + ) + max_retention_allowed: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=4, + message=duration_pb2.Duration, + ) + event_type: EventType = proto.Field( + proto.ENUM, + number=5, + enum=EventType, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/disk.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/disk.py new file mode 100644 index 000000000000..cf68fdfa0984 --- /dev/null +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/disk.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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. +# +from __future__ import annotations + +from typing import MutableMapping, MutableSequence + +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.securitycenter.v2", + manifest={ + "Disk", + }, +) + + +class Disk(proto.Message): + r"""Contains information about the disk associated with the + finding. + + Attributes: + name (str): + The name of the disk, for example, + ``https://www.googleapis.com/compute/v1/projects/{project-id}/zones/{zone-id}/disks/{disk-id}``. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/finding.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/finding.py index 1c6b7d9f07a0..f5a8e07f548c 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/finding.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/finding.py @@ -26,6 +26,9 @@ connection, contact_details, container, + data_access_event, + data_flow_event, + data_retention_deletion_event, ) from google.cloud.securitycenter_v2.types import ( external_system, @@ -58,6 +61,7 @@ from google.cloud.securitycenter_v2.types import application as gcs_application from google.cloud.securitycenter_v2.types import cloud_armor as gcs_cloud_armor from google.cloud.securitycenter_v2.types import database as gcs_database +from google.cloud.securitycenter_v2.types import disk as gcs_disk from google.cloud.securitycenter_v2.types import indicator as gcs_indicator from google.cloud.securitycenter_v2.types import kubernetes as gcs_kubernetes from google.cloud.securitycenter_v2.types import load_balancer, log_entry @@ -333,6 +337,16 @@ class Finding(proto.Message): findings that are related in some way. This field cannot be updated. Its value is ignored in all update requests. + disk (google.cloud.securitycenter_v2.types.Disk): + Disk associated with the finding. + data_access_events (MutableSequence[google.cloud.securitycenter_v2.types.DataAccessEvent]): + Data access events associated with the + finding. + data_flow_events (MutableSequence[google.cloud.securitycenter_v2.types.DataFlowEvent]): + Data flow events associated with the finding. + data_retention_deletion_events (MutableSequence[google.cloud.securitycenter_v2.types.DataRetentionDeletionEvent]): + Data retention deletion events associated + with the finding. """ class State(proto.Enum): @@ -488,6 +502,9 @@ class FindingClass(proto.Enum): Describes a combination of security issues that represent a more severe security problem when taken together. + SENSITIVE_DATA_RISK (8): + Describes a potential security risk to data + assets that contain sensitive data. """ FINDING_CLASS_UNSPECIFIED = 0 THREAT = 1 @@ -497,6 +514,7 @@ class FindingClass(proto.Enum): SCC_ERROR = 5 POSTURE_VIOLATION = 6 TOXIC_COMBINATION = 7 + SENSITIVE_DATA_RISK = 8 class MuteInfo(proto.Message): r"""Mute information about the finding, including whether the @@ -825,6 +843,32 @@ class DynamicMuteRecord(proto.Message): number=57, message=group_membership.GroupMembership, ) + disk: gcs_disk.Disk = proto.Field( + proto.MESSAGE, + number=58, + message=gcs_disk.Disk, + ) + data_access_events: MutableSequence[ + data_access_event.DataAccessEvent + ] = proto.RepeatedField( + proto.MESSAGE, + number=61, + message=data_access_event.DataAccessEvent, + ) + data_flow_events: MutableSequence[ + data_flow_event.DataFlowEvent + ] = proto.RepeatedField( + proto.MESSAGE, + number=62, + message=data_flow_event.DataFlowEvent, + ) + data_retention_deletion_events: MutableSequence[ + data_retention_deletion_event.DataRetentionDeletionEvent + ] = proto.RepeatedField( + proto.MESSAGE, + number=64, + message=data_retention_deletion_event.DataRetentionDeletionEvent, + ) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/mitre_attack.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/mitre_attack.py index 64e19b3268df..42ad69387cf5 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/mitre_attack.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/mitre_attack.py @@ -111,7 +111,6 @@ class Tactic(proto.Enum): class Technique(proto.Enum): r"""MITRE ATT&CK techniques that can be referenced by SCC findings. See: https://attack.mitre.org/techniques/enterprise/ - Next ID: 65 Values: TECHNIQUE_UNSPECIFIED (0): @@ -206,6 +205,8 @@ class Technique(proto.Enum): T1539 CREATE_OR_MODIFY_SYSTEM_PROCESS (24): T1543 + EVENT_TRIGGERED_EXECUTION (65): + T1546 ABUSE_ELEVATION_CONTROL_MECHANISM (34): T1548 UNSECURED_CREDENTIALS (13): @@ -238,6 +239,8 @@ class Technique(proto.Enum): T1595.001 CONTAINER_ADMINISTRATION_COMMAND (60): T1609 + DEPLOY_CONTAINER (66): + T1610 ESCAPE_TO_HOST (61): T1611 CONTAINER_AND_RESOURCE_DISCOVERY (57): @@ -291,6 +294,7 @@ class Technique(proto.Enum): ACCOUNT_ACCESS_REMOVAL = 51 STEAL_WEB_SESSION_COOKIE = 25 CREATE_OR_MODIFY_SYSTEM_PROCESS = 24 + EVENT_TRIGGERED_EXECUTION = 65 ABUSE_ELEVATION_CONTROL_MECHANISM = 34 UNSECURED_CREDENTIALS = 13 MODIFY_AUTHENTICATION_PROCESS = 28 @@ -307,6 +311,7 @@ class Technique(proto.Enum): ACTIVE_SCANNING = 1 SCANNING_IP_BLOCKS = 2 CONTAINER_ADMINISTRATION_COMMAND = 60 + DEPLOY_CONTAINER = 66 ESCAPE_TO_HOST = 61 CONTAINER_AND_RESOURCE_DISCOVERY = 57 STEAL_OR_FORGE_AUTHENTICATION_CERTIFICATES = 62 diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/org_policy.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/org_policy.py index d824b4712353..3e1e00121de3 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/org_policy.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/org_policy.py @@ -33,7 +33,7 @@ class OrgPolicy(proto.Message): Attributes: name (str): - The resource name of the org policy. Example: + Identifier. The resource name of the org policy. Example: "organizations/{organization_id}/policies/{constraint_name}". """ diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource.py index d4a3ea140b7a..eac1ee09f752 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource.py @@ -331,6 +331,9 @@ class AzureMetadata(proto.Message): resource_group (google.cloud.securitycenter_v2.types.AzureMetadata.AzureResourceGroup): The Azure resource group associated with the resource. + tenant (google.cloud.securitycenter_v2.types.AzureMetadata.AzureTenant): + The Azure Entra tenant associated with the + resource. """ class AzureManagementGroup(proto.Message): @@ -378,16 +381,42 @@ class AzureResourceGroup(proto.Message): r"""Represents an Azure resource group. Attributes: + id (str): + The ID of the Azure resource group. name (str): The name of the Azure resource group. This is not a UUID. """ + id: str = proto.Field( + proto.STRING, + number=2, + ) name: str = proto.Field( proto.STRING, number=1, ) + class AzureTenant(proto.Message): + r"""Represents a Microsoft Entra tenant. + + Attributes: + id (str): + The ID of the Microsoft Entra tenant, for + example, "a11aaa11-aa11-1aa1-11aa-1aaa11a". + display_name (str): + The display name of the Azure tenant. + """ + + id: str = proto.Field( + proto.STRING, + number=1, + ) + display_name: str = proto.Field( + proto.STRING, + number=2, + ) + management_groups: MutableSequence[AzureManagementGroup] = proto.RepeatedField( proto.MESSAGE, number=1, @@ -403,6 +432,11 @@ class AzureResourceGroup(proto.Message): number=3, message=AzureResourceGroup, ) + tenant: AzureTenant = proto.Field( + proto.MESSAGE, + number=7, + message=AzureTenant, + ) class ResourcePath(proto.Message): diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource_value_config.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource_value_config.py index 5c8a7048f653..6abe62b710b0 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource_value_config.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/resource_value_config.py @@ -68,8 +68,9 @@ class ResourceValueConfig(proto.Message): represents Only required when there is no Sensitive Data Protection mapping in the request tag_values (MutableSequence[str]): - Tag values combined with ``AND`` to check against. Values in - the form "tagValues/123" Example: + Tag values combined with ``AND`` to check against. For + Google Cloud resources, they are tag value IDs in the form + of "tagValues/123". Example: ``[ "tagValues/123", "tagValues/456", "tagValues/789" ]`` https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing resource_type (str): diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/vulnerability.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/vulnerability.py index 6fc4b6ed3216..7cdcdef91a21 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/vulnerability.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/types/vulnerability.py @@ -109,6 +109,8 @@ class Cve(proto.Message): exploit_release_date (google.protobuf.timestamp_pb2.Timestamp): Date the first publicly available exploit or PoC was released. + first_exploitation_date (google.protobuf.timestamp_pb2.Timestamp): + Date of the earliest known exploitation. """ class RiskRating(proto.Enum): @@ -212,6 +214,11 @@ class ExploitationActivity(proto.Enum): number=9, message=timestamp_pb2.Timestamp, ) + first_exploitation_date: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=10, + message=timestamp_pb2.Timestamp, + ) class Reference(proto.Message): diff --git a/packages/google-cloud-securitycenter/tests/unit/gapic/securitycenter_v2/test_security_center.py b/packages/google-cloud-securitycenter/tests/unit/gapic/securitycenter_v2/test_security_center.py index 7cb77cd029cc..0cd034cea472 100644 --- a/packages/google-cloud-securitycenter/tests/unit/gapic/securitycenter_v2/test_security_center.py +++ b/packages/google-cloud-securitycenter/tests/unit/gapic/securitycenter_v2/test_security_center.py @@ -91,7 +91,11 @@ connection, contact_details, container, + data_access_event, + data_flow_event, + data_retention_deletion_event, database, + disk, exfiltration, ) from google.cloud.securitycenter_v2.types import ( @@ -29030,6 +29034,7 @@ def test_create_finding_rest_call_success(request_type): "observed_in_the_wild": True, "zero_day": True, "exploit_release_date": {}, + "first_exploitation_date": {}, }, "offending_package": { "package_name": "package_name_value", @@ -29268,9 +29273,11 @@ def test_create_finding_rest_call_success(request_type): }, "adaptive_protection": {"confidence": 0.1038}, "attack": { + "volume_pps_long": 1625, + "volume_bps_long": 1611, + "classification": "classification_value", "volume_pps": 1098, "volume_bps": 1084, - "classification": "classification_value", }, "threat_vector": "threat_vector_value", "duration": {"seconds": 751, "nanos": 543}, @@ -29286,6 +29293,32 @@ def test_create_finding_rest_call_success(request_type): "related_findings": ["related_findings_value1", "related_findings_value2"], }, "group_memberships": [{"group_type": 1, "group_id": "group_id_value"}], + "disk": {"name": "name_value"}, + "data_access_events": [ + { + "event_id": "event_id_value", + "principal_email": "principal_email_value", + "operation": 1, + "event_time": {}, + } + ], + "data_flow_events": [ + { + "event_id": "event_id_value", + "principal_email": "principal_email_value", + "operation": 1, + "violated_location": "violated_location_value", + "event_time": {}, + } + ], + "data_retention_deletion_events": [ + { + "event_detection_time": {}, + "data_object_count": 1784, + "max_retention_allowed": {}, + "event_type": 1, + } + ], } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -33986,6 +34019,7 @@ def test_update_finding_rest_call_success(request_type): "observed_in_the_wild": True, "zero_day": True, "exploit_release_date": {}, + "first_exploitation_date": {}, }, "offending_package": { "package_name": "package_name_value", @@ -34224,9 +34258,11 @@ def test_update_finding_rest_call_success(request_type): }, "adaptive_protection": {"confidence": 0.1038}, "attack": { + "volume_pps_long": 1625, + "volume_bps_long": 1611, + "classification": "classification_value", "volume_pps": 1098, "volume_bps": 1084, - "classification": "classification_value", }, "threat_vector": "threat_vector_value", "duration": {"seconds": 751, "nanos": 543}, @@ -34242,6 +34278,32 @@ def test_update_finding_rest_call_success(request_type): "related_findings": ["related_findings_value1", "related_findings_value2"], }, "group_memberships": [{"group_type": 1, "group_id": "group_id_value"}], + "disk": {"name": "name_value"}, + "data_access_events": [ + { + "event_id": "event_id_value", + "principal_email": "principal_email_value", + "operation": 1, + "event_time": {}, + } + ], + "data_flow_events": [ + { + "event_id": "event_id_value", + "principal_email": "principal_email_value", + "operation": 1, + "violated_location": "violated_location_value", + "event_time": {}, + } + ], + "data_retention_deletion_events": [ + { + "event_detection_time": {}, + "data_object_count": 1784, + "max_retention_allowed": {}, + "event_type": 1, + } + ], } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency From 03649eb7f4b41de2981b1d49e7a6fc2bf20686d1 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:52:25 +0500 Subject: [PATCH 06/13] feat: [google-cloud-parallelstore] deprecating `daos_version` field (#13528) BEGIN_COMMIT_OVERRIDE feat: deprecating `daos_version` field feat: Adding `deployment_type` field docs: updated documentation for field `daos_version` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is deprecated. docs: Updated field `file_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflected that message is now immutable docs: updated `directory_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is now immutable END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. feat: Adding `deployment_type` field docs: updated documentation for field `daos_version` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is deprecated. docs: Updated field `file_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflected that message is now immutable docs: updated `directory_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is now immutable PiperOrigin-RevId: 726614548 Source-Link: https://github.com/googleapis/googleapis/commit/a003cab30e2a263e16e9252256041f8934f40e2c Source-Link: https://github.com/googleapis/googleapis-gen/commit/0987b560a03ccc97202919d3290048837f2ae6d2 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBhcmFsbGVsc3RvcmUvLk93bEJvdC55YW1sIiwiaCI6IjA5ODdiNTYwYTAzY2NjOTcyMDI5MTlkMzI5MDA0ODgzN2YyYWU2ZDIifQ== --------- Co-authored-by: Owl Bot --- .../google-cloud-parallelstore/README.rst | 4 +- .../cloud/parallelstore/gapic_version.py | 2 +- .../google/cloud/parallelstore_v1/__init__.py | 6 + .../cloud/parallelstore_v1/gapic_version.py | 2 +- .../cloud/parallelstore_v1/types/__init__.py | 6 + .../parallelstore_v1/types/parallelstore.py | 123 +++++++++++++++++- .../parallelstore_v1beta/gapic_version.py | 2 +- .../google-cloud-parallelstore/noxfile.py | 81 +++++++++++- ...etadata_google.cloud.parallelstore.v1.json | 2 +- ...ata_google.cloud.parallelstore.v1beta.json | 2 +- .../parallelstore_v1/test_parallelstore.py | 9 ++ 11 files changed, 226 insertions(+), 13 deletions(-) diff --git a/packages/google-cloud-parallelstore/README.rst b/packages/google-cloud-parallelstore/README.rst index 652c7a5e5c08..2c2f043188ca 100644 --- a/packages/google-cloud-parallelstore/README.rst +++ b/packages/google-cloud-parallelstore/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Parallelstore API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Parallelstore API.: https://cloud.google.com/parallelstore -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py index 5d1aa0887dd3..558c8aab67c5 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/__init__.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/__init__.py index 0300bbd36217..18de3efbd9f7 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/__init__.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/__init__.py @@ -22,6 +22,7 @@ from .types.parallelstore import ( CreateInstanceRequest, DeleteInstanceRequest, + DeploymentType, DestinationGcsBucket, DestinationParallelstore, DirectoryStripeLevel, @@ -40,6 +41,8 @@ SourceGcsBucket, SourceParallelstore, TransferCounters, + TransferErrorLogEntry, + TransferErrorSummary, TransferOperationMetadata, TransferType, UpdateInstanceRequest, @@ -49,6 +52,7 @@ "ParallelstoreAsyncClient", "CreateInstanceRequest", "DeleteInstanceRequest", + "DeploymentType", "DestinationGcsBucket", "DestinationParallelstore", "DirectoryStripeLevel", @@ -68,6 +72,8 @@ "SourceGcsBucket", "SourceParallelstore", "TransferCounters", + "TransferErrorLogEntry", + "TransferErrorSummary", "TransferOperationMetadata", "TransferType", "UpdateInstanceRequest", diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py index 5d1aa0887dd3..558c8aab67c5 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/__init__.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/__init__.py index faadce2e0eff..799ef8d0c43f 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/__init__.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/__init__.py @@ -16,6 +16,7 @@ from .parallelstore import ( CreateInstanceRequest, DeleteInstanceRequest, + DeploymentType, DestinationGcsBucket, DestinationParallelstore, DirectoryStripeLevel, @@ -34,6 +35,8 @@ SourceGcsBucket, SourceParallelstore, TransferCounters, + TransferErrorLogEntry, + TransferErrorSummary, TransferOperationMetadata, TransferType, UpdateInstanceRequest, @@ -58,8 +61,11 @@ "SourceGcsBucket", "SourceParallelstore", "TransferCounters", + "TransferErrorLogEntry", + "TransferErrorSummary", "TransferOperationMetadata", "UpdateInstanceRequest", + "DeploymentType", "DirectoryStripeLevel", "FileStripeLevel", "TransferType", diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/parallelstore.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/parallelstore.py index e70889beb8f8..bd6b20c437d7 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/parallelstore.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/types/parallelstore.py @@ -19,6 +19,7 @@ from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.rpc import code_pb2 # type: ignore import proto # type: ignore __protobuf__ = proto.module( @@ -27,6 +28,7 @@ "TransferType", "FileStripeLevel", "DirectoryStripeLevel", + "DeploymentType", "Instance", "ListInstancesRequest", "ListInstancesResponse", @@ -42,6 +44,8 @@ "ImportDataRequest", "ExportDataRequest", "ImportDataResponse", + "TransferErrorLogEntry", + "TransferErrorSummary", "ImportDataMetadata", "ExportDataResponse", "ExportDataMetadata", @@ -107,6 +111,23 @@ class DirectoryStripeLevel(proto.Enum): DIRECTORY_STRIPE_LEVEL_MAX = 3 +class DeploymentType(proto.Enum): + r"""Represents the deployment type for the instance. + + Values: + DEPLOYMENT_TYPE_UNSPECIFIED (0): + Default Deployment Type + It is equivalent to SCRATCH + SCRATCH (1): + Scratch + PERSISTENT (2): + Persistent + """ + DEPLOYMENT_TYPE_UNSPECIFIED = 0 + SCRATCH = 1 + PERSISTENT = 2 + + class Instance(proto.Message): r"""A Parallelstore instance. @@ -139,8 +160,8 @@ class Instance(proto.Message): between 12000 and 100000, in multiples of 4000; e.g., 12000, 16000, 20000, ... daos_version (str): - Output only. The version of DAOS software - running in the instance. + Deprecated 'daos_version' field. Output only. The version of + DAOS software running in the instance. access_points (MutableSequence[str]): Output only. A list of IPv4 addresses used for client side configuration. @@ -160,7 +181,8 @@ class Instance(proto.Message): and contains the value currently used by the service. file_stripe_level (google.cloud.parallelstore_v1.types.FileStripeLevel): - Optional. Stripe level for files. Allowed values are: + Optional. Immutable. Stripe level for files. Allowed values + are: - ``FILE_STRIPE_LEVEL_MIN``: offers the best performance for small size files. @@ -169,7 +191,8 @@ class Instance(proto.Message): - ``FILE_STRIPE_LEVEL_MAX``: higher throughput performance for larger files. directory_stripe_level (google.cloud.parallelstore_v1.types.DirectoryStripeLevel): - Optional. Stripe level for directories. Allowed values are: + Optional. Immutable. Stripe level for directories. Allowed + values are: - ``DIRECTORY_STRIPE_LEVEL_MIN``: recommended when directories contain a small number of files. @@ -178,6 +201,12 @@ class Instance(proto.Message): directories. - ``DIRECTORY_STRIPE_LEVEL_MAX``: recommended for directories with a large number of files. + deployment_type (google.cloud.parallelstore_v1.types.DeploymentType): + Optional. Immutable. The deployment type of the instance. + Allowed values are: + + - ``SCRATCH``: the instance is a scratch instance. + - ``PERSISTENT``: the instance is a persistent instance. """ class State(proto.Enum): @@ -196,6 +225,9 @@ class State(proto.Enum): The instance is not usable. UPGRADING (5): The instance is being upgraded. + REPAIRING (6): + The instance is being repaired. This should only be used by + instances using the ``PERSISTENT`` deployment type. """ STATE_UNSPECIFIED = 0 CREATING = 1 @@ -203,6 +235,7 @@ class State(proto.Enum): DELETING = 3 FAILED = 4 UPGRADING = 5 + REPAIRING = 6 name: str = proto.Field( proto.STRING, @@ -266,6 +299,11 @@ class State(proto.Enum): number=16, enum="DirectoryStripeLevel", ) + deployment_type: "DeploymentType" = proto.Field( + proto.ENUM, + number=17, + enum="DeploymentType", + ) class ListInstancesRequest(proto.Message): @@ -792,6 +830,60 @@ class ImportDataResponse(proto.Message): r"""The response to a request to import data to Parallelstore.""" +class TransferErrorLogEntry(proto.Message): + r"""An entry describing an error that has occurred. + + Attributes: + uri (str): + A URL that refers to the target (a data + source, a data sink, or an object) with which + the error is associated. + error_details (MutableSequence[str]): + A list of messages that carry the error + details. + """ + + uri: str = proto.Field( + proto.STRING, + number=1, + ) + error_details: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=2, + ) + + +class TransferErrorSummary(proto.Message): + r"""A summary of errors by error code, plus a count and sample + error log entries. + + Attributes: + error_code (google.rpc.code_pb2.Code): + One of the error codes that caused the + transfer failure. + error_count (int): + Count of this type of error. + error_log_entries (MutableSequence[google.cloud.parallelstore_v1.types.TransferErrorLogEntry]): + A list of messages that carry the error + details. + """ + + error_code: code_pb2.Code = proto.Field( + proto.ENUM, + number=1, + enum=code_pb2.Code, + ) + error_count: int = proto.Field( + proto.INT64, + number=2, + ) + error_log_entries: MutableSequence["TransferErrorLogEntry"] = proto.RepeatedField( + proto.MESSAGE, + number=4, + message="TransferErrorLogEntry", + ) + + class ImportDataMetadata(proto.Message): r"""Metadata related to the data import operation. @@ -968,6 +1060,10 @@ class TransferOperationMetadata(proto.Message): operation. transfer_type (google.cloud.parallelstore_v1.types.TransferType): Output only. The type of transfer occurring. + error_summary (MutableSequence[google.cloud.parallelstore_v1.types.TransferErrorSummary]): + Output only. List of files that failed to be + transferred. This list will have a maximum size + of 5 elements. """ source_parallelstore: "SourceParallelstore" = proto.Field( @@ -1004,6 +1100,11 @@ class TransferOperationMetadata(proto.Message): number=6, enum="TransferType", ) + error_summary: MutableSequence["TransferErrorSummary"] = proto.RepeatedField( + proto.MESSAGE, + number=13, + message="TransferErrorSummary", + ) class TransferCounters(proto.Message): @@ -1035,6 +1136,12 @@ class TransferCounters(proto.Message): bytes_copied (int): Bytes that are copied to the data destination. + objects_failed (int): + Objects that failed to write to the data + destination. + bytes_failed (int): + Number of Bytes that failed to be written to + the data destination. """ objects_found: int = proto.Field( @@ -1061,6 +1168,14 @@ class TransferCounters(proto.Message): proto.INT64, number=6, ) + objects_failed: int = proto.Field( + proto.INT64, + number=7, + ) + bytes_failed: int = proto.Field( + proto.INT64, + number=8, + ) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py index 5d1aa0887dd3..558c8aab67c5 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.2.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/noxfile.py b/packages/google-cloud-parallelstore/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-parallelstore/noxfile.py +++ b/packages/google-cloud-parallelstore/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json index 26c9fa46ad41..30bc2a5b8355 100644 --- a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json +++ b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-parallelstore", - "version": "0.2.10" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json index f6f1f7bbbc0a..db5492278bf9 100644 --- a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json +++ b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-parallelstore", - "version": "0.2.10" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-parallelstore/tests/unit/gapic/parallelstore_v1/test_parallelstore.py b/packages/google-cloud-parallelstore/tests/unit/gapic/parallelstore_v1/test_parallelstore.py index 8fe593d5c9a4..14e1dae067c5 100644 --- a/packages/google-cloud-parallelstore/tests/unit/gapic/parallelstore_v1/test_parallelstore.py +++ b/packages/google-cloud-parallelstore/tests/unit/gapic/parallelstore_v1/test_parallelstore.py @@ -1679,6 +1679,7 @@ def test_get_instance(request_type, transport: str = "grpc"): effective_reserved_ip_range="effective_reserved_ip_range_value", file_stripe_level=parallelstore.FileStripeLevel.FILE_STRIPE_LEVEL_MIN, directory_stripe_level=parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN, + deployment_type=parallelstore.DeploymentType.SCRATCH, ) response = client.get_instance(request) @@ -1707,6 +1708,7 @@ def test_get_instance(request_type, transport: str = "grpc"): response.directory_stripe_level == parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN ) + assert response.deployment_type == parallelstore.DeploymentType.SCRATCH def test_get_instance_non_empty_request_with_auto_populated_field(): @@ -1843,6 +1845,7 @@ async def test_get_instance_async( effective_reserved_ip_range="effective_reserved_ip_range_value", file_stripe_level=parallelstore.FileStripeLevel.FILE_STRIPE_LEVEL_MIN, directory_stripe_level=parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN, + deployment_type=parallelstore.DeploymentType.SCRATCH, ) ) response = await client.get_instance(request) @@ -1872,6 +1875,7 @@ async def test_get_instance_async( response.directory_stripe_level == parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN ) + assert response.deployment_type == parallelstore.DeploymentType.SCRATCH @pytest.mark.asyncio @@ -5123,6 +5127,7 @@ async def test_get_instance_empty_call_grpc_asyncio(): effective_reserved_ip_range="effective_reserved_ip_range_value", file_stripe_level=parallelstore.FileStripeLevel.FILE_STRIPE_LEVEL_MIN, directory_stripe_level=parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN, + deployment_type=parallelstore.DeploymentType.SCRATCH, ) ) await client.get_instance(request=None) @@ -5455,6 +5460,7 @@ def test_get_instance_rest_call_success(request_type): effective_reserved_ip_range="effective_reserved_ip_range_value", file_stripe_level=parallelstore.FileStripeLevel.FILE_STRIPE_LEVEL_MIN, directory_stripe_level=parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN, + deployment_type=parallelstore.DeploymentType.SCRATCH, ) # Wrap the value into a proper Response obj @@ -5488,6 +5494,7 @@ def test_get_instance_rest_call_success(request_type): response.directory_stripe_level == parallelstore.DirectoryStripeLevel.DIRECTORY_STRIPE_LEVEL_MIN ) + assert response.deployment_type == parallelstore.DeploymentType.SCRATCH @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -5606,6 +5613,7 @@ def test_create_instance_rest_call_success(request_type): "effective_reserved_ip_range": "effective_reserved_ip_range_value", "file_stripe_level": 1, "directory_stripe_level": 1, + "deployment_type": 1, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -5816,6 +5824,7 @@ def test_update_instance_rest_call_success(request_type): "effective_reserved_ip_range": "effective_reserved_ip_range_value", "file_stripe_level": 1, "directory_stripe_level": 1, + "deployment_type": 1, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency From 0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:54:25 +0500 Subject: [PATCH 07/13] chore: [google-cloud-vm-migration,google-cloud-vmwareengine,google-cloud-workstations] Update gapic-generator-python to v1.22.1 (#13525) BEGIN_COMMIT_OVERRIDE chore: Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. fix(deps): Require grpc-google-iam-v1>=0.14.0 PiperOrigin-RevId: 726142856 Source-Link: https://github.com/googleapis/googleapis/commit/25989cb753bf7d69ee446bda9d9794b61912707d Source-Link: https://github.com/googleapis/googleapis-gen/commit/677041b91cef1598cc55727d59a2804b198a5bbf Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXZtLW1pZ3JhdGlvbi8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXZtd2FyZWVuZ2luZS8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXdvcmtzdGF0aW9ucy8uT3dsQm90LnlhbWwiLCJoIjoiNjc3MDQxYjkxY2VmMTU5OGNjNTU3MjdkNTlhMjgwNGIxOThhNWJiZiJ9 --------- Co-authored-by: Owl Bot --- packages/google-cloud-vm-migration/README.rst | 4 +- .../google/cloud/vmmigration/gapic_version.py | 2 +- .../cloud/vmmigration_v1/gapic_version.py | 2 +- packages/google-cloud-vm-migration/noxfile.py | 81 ++++++++++++++++++- ..._metadata_google.cloud.vmmigration.v1.json | 2 +- packages/google-cloud-vm-migration/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-vmwareengine/README.rst | 4 +- .../cloud/vmwareengine/gapic_version.py | 2 +- .../cloud/vmwareengine_v1/gapic_version.py | 2 +- packages/google-cloud-vmwareengine/noxfile.py | 81 ++++++++++++++++++- ...metadata_google.cloud.vmwareengine.v1.json | 2 +- packages/google-cloud-vmwareengine/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- packages/google-cloud-workstations/README.rst | 4 +- .../cloud/workstations/gapic_version.py | 2 +- .../cloud/workstations_v1/gapic_version.py | 2 +- .../workstations_v1beta/gapic_version.py | 2 +- packages/google-cloud-workstations/noxfile.py | 81 ++++++++++++++++++- ...metadata_google.cloud.workstations.v1.json | 2 +- ...data_google.cloud.workstations.v1beta.json | 2 +- packages/google-cloud-workstations/setup.py | 2 +- .../testing/constraints-3.7.txt | 2 +- 23 files changed, 260 insertions(+), 29 deletions(-) diff --git a/packages/google-cloud-vm-migration/README.rst b/packages/google-cloud-vm-migration/README.rst index 1ca88d8abe65..57024130a984 100644 --- a/packages/google-cloud-vm-migration/README.rst +++ b/packages/google-cloud-vm-migration/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud VM Migration.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud VM Migration.: https://cloud.google.com/migrate/compute-engine/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py b/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py index 50d842f376d0..558c8aab67c5 100644 --- a/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py +++ b/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.11.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py b/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py index 50d842f376d0..558c8aab67c5 100644 --- a/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py +++ b/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.11.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-vm-migration/noxfile.py b/packages/google-cloud-vm-migration/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-vm-migration/noxfile.py +++ b/packages/google-cloud-vm-migration/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json b/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json index 243c6d5c9c0c..cfb6d660b704 100644 --- a/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json +++ b/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-vm-migration", - "version": "1.11.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-vm-migration/setup.py b/packages/google-cloud-vm-migration/setup.py index 01bd735ebaf0..d6443b1d57c0 100644 --- a/packages/google-cloud-vm-migration/setup.py +++ b/packages/google-cloud-vm-migration/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vm-migration" diff --git a/packages/google-cloud-vm-migration/testing/constraints-3.7.txt b/packages/google-cloud-vm-migration/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-vm-migration/testing/constraints-3.7.txt +++ b/packages/google-cloud-vm-migration/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-vmwareengine/README.rst b/packages/google-cloud-vmwareengine/README.rst index b490e98e15de..c6e31cc52e99 100644 --- a/packages/google-cloud-vmwareengine/README.rst +++ b/packages/google-cloud-vmwareengine/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud VMware Engine.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud VMware Engine.: https://cloud.google.com/vmware-engine/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py index 4b114d153974..558c8aab67c5 100644 --- a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py +++ b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.8.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py index 4b114d153974..558c8aab67c5 100644 --- a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py +++ b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.8.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-vmwareengine/noxfile.py b/packages/google-cloud-vmwareengine/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-vmwareengine/noxfile.py +++ b/packages/google-cloud-vmwareengine/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json b/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json index fae9afc43bba..6d234586a410 100644 --- a/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json +++ b/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-vmwareengine", - "version": "1.8.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-vmwareengine/setup.py b/packages/google-cloud-vmwareengine/setup.py index 90c683916e2d..0d2ae13da5e0 100644 --- a/packages/google-cloud-vmwareengine/setup.py +++ b/packages/google-cloud-vmwareengine/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vmwareengine" diff --git a/packages/google-cloud-vmwareengine/testing/constraints-3.7.txt b/packages/google-cloud-vmwareengine/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-vmwareengine/testing/constraints-3.7.txt +++ b/packages/google-cloud-vmwareengine/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 diff --git a/packages/google-cloud-workstations/README.rst b/packages/google-cloud-workstations/README.rst index cb4da964bb9c..3dd0c4ad7ea2 100644 --- a/packages/google-cloud-workstations/README.rst +++ b/packages/google-cloud-workstations/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Workstations.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Workstations.: https://cloud.google.com/workstations/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py index cc43a639a105..558c8aab67c5 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py index cc43a639a105..558c8aab67c5 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py index cc43a639a105..558c8aab67c5 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.5.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/noxfile.py b/packages/google-cloud-workstations/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-workstations/noxfile.py +++ b/packages/google-cloud-workstations/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json index 717f60963fd7..c9f644c1d20c 100644 --- a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json +++ b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-workstations", - "version": "0.5.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json index b587c6211445..2a6523f2cb2d 100644 --- a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json +++ b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-workstations", - "version": "0.5.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-workstations/setup.py b/packages/google-cloud-workstations/setup.py index 329686704260..59dcba363f5c 100644 --- a/packages/google-cloud-workstations/setup.py +++ b/packages/google-cloud-workstations/setup.py @@ -48,7 +48,7 @@ "proto-plus >= 1.22.3, <2.0.0dev", "proto-plus >= 1.25.0, <2.0.0dev; python_version >= '3.13'", "protobuf>=3.20.2,<6.0.0dev,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", - "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", + "grpc-google-iam-v1 >= 0.14.0, <1.0.0dev", ] extras = {} url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-workstations" diff --git a/packages/google-cloud-workstations/testing/constraints-3.7.txt b/packages/google-cloud-workstations/testing/constraints-3.7.txt index a81fb6bcd05c..fb7e93a1b473 100644 --- a/packages/google-cloud-workstations/testing/constraints-3.7.txt +++ b/packages/google-cloud-workstations/testing/constraints-3.7.txt @@ -8,4 +8,4 @@ google-api-core==1.34.1 google-auth==2.14.1 proto-plus==1.22.3 protobuf==3.20.2 -grpc-google-iam-v1==0.12.4 +grpc-google-iam-v1==0.14.0 From 3fe88999b3f56faeae0c8f36b4fe8f750d168f18 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:02:41 +0500 Subject: [PATCH 08/13] feat: [google-cloud-build] Support for git proxy setup (#13520) BEGIN_COMMIT_OVERRIDE feat: Add option to enable fetching dependencies chore: Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 feat: Support for git proxy setup docs: Updates to proto message comments END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. docs: Updates to proto message comments PiperOrigin-RevId: 726194972 Source-Link: https://github.com/googleapis/googleapis/commit/da30f52583f070f676ed886ed9e33d84a646f74c Source-Link: https://github.com/googleapis/googleapis-gen/commit/5207ef8b8aaeef9cb31577b78c6083d68ced159a Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJ1aWxkLy5Pd2xCb3QueWFtbCIsImgiOiI1MjA3ZWY4YjhhYWVlZjljYjMxNTc3Yjc4YzYwODNkNjhjZWQxNTlhIn0= BEGIN_NESTED_COMMIT chore: [google-cloud-build] Update gapic-generator-python to v1.22.1 fix(deps): Require grpc-google-iam-v1>=0.14.0 PiperOrigin-RevId: 726142856 Source-Link: https://github.com/googleapis/googleapis/commit/25989cb753bf7d69ee446bda9d9794b61912707d Source-Link: https://github.com/googleapis/googleapis-gen/commit/677041b91cef1598cc55727d59a2804b198a5bbf Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJ1aWxkLy5Pd2xCb3QueWFtbCIsImgiOiI2NzcwNDFiOTFjZWYxNTk4Y2M1NTcyN2Q1OWEyODA0YjE5OGE1YmJmIn0= END_NESTED_COMMIT BEGIN_NESTED_COMMIT feat: [google-cloud-build] Add option to enable fetching dependencies PiperOrigin-RevId: 726044205 Source-Link: https://github.com/googleapis/googleapis/commit/8c6501214a223ef031eeb81e558abddf34cc046c Source-Link: https://github.com/googleapis/googleapis-gen/commit/c576e37172d85d4756151ace04dcb1e8456bf1de Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJ1aWxkLy5Pd2xCb3QueWFtbCIsImgiOiJjNTc2ZTM3MTcyZDg1ZDQ3NTYxNTFhY2UwNGRjYjFlODQ1NmJmMWRlIn0= END_NESTED_COMMIT --------- Co-authored-by: Owl Bot --- packages/google-cloud-build/README.rst | 4 +- .../cloud/devtools/cloudbuild/__init__.py | 4 + .../cloud/devtools/cloudbuild_v1/__init__.py | 4 + .../services/cloud_build/async_client.py | 4 + .../services/cloud_build/client.py | 24 ++ .../devtools/cloudbuild_v1/types/__init__.py | 4 + .../cloudbuild_v1/types/cloudbuild.py | 233 ++++++++++++++++-- packages/google-cloud-build/noxfile.py | 81 +++++- .../gapic/cloudbuild_v1/test_cloud_build.py | 193 +++++++++++---- 9 files changed, 473 insertions(+), 78 deletions(-) diff --git a/packages/google-cloud-build/README.rst b/packages/google-cloud-build/README.rst index 8323ef82e8af..a913bda5323e 100644 --- a/packages/google-cloud-build/README.rst +++ b/packages/google-cloud-build/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Build.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Build.: https://cloud.google.com/cloud-build/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild/__init__.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild/__init__.py index ec010bed1b50..c46401f14e33 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild/__init__.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild/__init__.py @@ -45,10 +45,12 @@ DeleteBuildTriggerRequest, DeleteWorkerPoolOperationMetadata, DeleteWorkerPoolRequest, + Dependency, FileHashes, GetBuildRequest, GetBuildTriggerRequest, GetWorkerPoolRequest, + GitConfig, GitFileSource, GitHubEnterpriseConfig, GitHubEnterpriseSecrets, @@ -117,10 +119,12 @@ "DeleteBuildTriggerRequest", "DeleteWorkerPoolOperationMetadata", "DeleteWorkerPoolRequest", + "Dependency", "FileHashes", "GetBuildRequest", "GetBuildTriggerRequest", "GetWorkerPoolRequest", + "GitConfig", "GitFileSource", "GitHubEnterpriseConfig", "GitHubEnterpriseSecrets", diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/__init__.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/__init__.py index ba562f8613dd..9b9c76f7dc98 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/__init__.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/__init__.py @@ -40,10 +40,12 @@ DeleteBuildTriggerRequest, DeleteWorkerPoolOperationMetadata, DeleteWorkerPoolRequest, + Dependency, FileHashes, GetBuildRequest, GetBuildTriggerRequest, GetWorkerPoolRequest, + GitConfig, GitFileSource, GitHubEnterpriseConfig, GitHubEnterpriseSecrets, @@ -112,10 +114,12 @@ "DeleteBuildTriggerRequest", "DeleteWorkerPoolOperationMetadata", "DeleteWorkerPoolRequest", + "Dependency", "FileHashes", "GetBuildRequest", "GetBuildTriggerRequest", "GetWorkerPoolRequest", + "GitConfig", "GitFileSource", "GitHubEnterpriseConfig", "GitHubEnterpriseSecrets", diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/async_client.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/async_client.py index 060166408631..6dc781d418cf 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/async_client.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/async_client.py @@ -99,6 +99,10 @@ class CloudBuildAsyncClient: parse_github_enterprise_config_path = staticmethod( CloudBuildClient.parse_github_enterprise_config_path ) + git_repository_link_path = staticmethod(CloudBuildClient.git_repository_link_path) + parse_git_repository_link_path = staticmethod( + CloudBuildClient.parse_git_repository_link_path + ) network_path = staticmethod(CloudBuildClient.network_path) parse_network_path = staticmethod(CloudBuildClient.parse_network_path) network_attachment_path = staticmethod(CloudBuildClient.network_attachment_path) diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/client.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/client.py index ce824b0d6df8..a2011022c1d2 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/client.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/services/cloud_build/client.py @@ -285,6 +285,30 @@ def parse_github_enterprise_config_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def git_repository_link_path( + project: str, + location: str, + connection: str, + git_repository_link: str, + ) -> str: + """Returns a fully-qualified git_repository_link string.""" + return "projects/{project}/locations/{location}/connections/{connection}/gitRepositoryLinks/{git_repository_link}".format( + project=project, + location=location, + connection=connection, + git_repository_link=git_repository_link, + ) + + @staticmethod + def parse_git_repository_link_path(path: str) -> Dict[str, str]: + """Parses a git_repository_link path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/connections/(?P.+?)/gitRepositoryLinks/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def network_path( project: str, diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/__init__.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/__init__.py index bbe931345c88..27a05b890c64 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/__init__.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/__init__.py @@ -34,10 +34,12 @@ DeleteBuildTriggerRequest, DeleteWorkerPoolOperationMetadata, DeleteWorkerPoolRequest, + Dependency, FileHashes, GetBuildRequest, GetBuildTriggerRequest, GetWorkerPoolRequest, + GitConfig, GitFileSource, GitHubEnterpriseConfig, GitHubEnterpriseSecrets, @@ -104,10 +106,12 @@ "DeleteBuildTriggerRequest", "DeleteWorkerPoolOperationMetadata", "DeleteWorkerPoolRequest", + "Dependency", "FileHashes", "GetBuildRequest", "GetBuildTriggerRequest", "GetWorkerPoolRequest", + "GitConfig", "GitFileSource", "GitHubEnterpriseConfig", "GitHubEnterpriseSecrets", diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/cloudbuild.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/cloudbuild.py index 11d51f57d8ab..0f353d04d3a2 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/cloudbuild.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/types/cloudbuild.py @@ -43,6 +43,8 @@ "Results", "ArtifactResult", "Build", + "Dependency", + "GitConfig", "Artifacts", "TimeSpan", "BuildOperationMetadata", @@ -856,8 +858,9 @@ class Results(proto.Message): `Cloud Builders `__ can produce this output by writing to - ``$BUILDER_OUTPUT/output``. Only the first 4KB of data is - stored. + ``$BUILDER_OUTPUT/output``. Only the first 50KB of data is + stored. Note that the ``$BUILDER_OUTPUT`` variable is + read-only and can't be substituted. artifact_timing (google.cloud.devtools.cloudbuild_v1.types.TimeSpan): Time to push all non-container artifacts to Cloud Storage. @@ -1087,9 +1090,14 @@ class Build(proto.Message): warnings (MutableSequence[google.cloud.devtools.cloudbuild_v1.types.Build.Warning]): Output only. Non-fatal problems encountered during the execution of the build. + git_config (google.cloud.devtools.cloudbuild_v1.types.GitConfig): + Optional. Configuration for git operations. failure_info (google.cloud.devtools.cloudbuild_v1.types.Build.FailureInfo): Output only. Contains information about the build when status=FAILURE. + dependencies (MutableSequence[google.cloud.devtools.cloudbuild_v1.types.Dependency]): + Optional. Dependencies that the Cloud Build + worker will fetch before executing user steps. """ class Status(proto.Enum): @@ -1356,11 +1364,171 @@ class FailureType(proto.Enum): number=49, message=Warning, ) + git_config: "GitConfig" = proto.Field( + proto.MESSAGE, + number=48, + message="GitConfig", + ) failure_info: FailureInfo = proto.Field( proto.MESSAGE, number=51, message=FailureInfo, ) + dependencies: MutableSequence["Dependency"] = proto.RepeatedField( + proto.MESSAGE, + number=56, + message="Dependency", + ) + + +class Dependency(proto.Message): + r"""A dependency that the Cloud Build worker will fetch before + executing user steps. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + empty (bool): + If set to true disable all dependency + fetching (ignoring the default source as well). + + This field is a member of `oneof`_ ``dep``. + git_source (google.cloud.devtools.cloudbuild_v1.types.Dependency.GitSourceDependency): + Represents a git repository as a build + dependency. + + This field is a member of `oneof`_ ``dep``. + """ + + class GitSourceDependency(proto.Message): + r"""Represents a git repository as a build dependency. + + Attributes: + repository (google.cloud.devtools.cloudbuild_v1.types.Dependency.GitSourceRepository): + Required. The kind of repo (url or dev + connect). + revision (str): + Required. The revision that we will fetch the + repo at. + recurse_submodules (bool): + Optional. True if submodules should be + fetched too (default false). + depth (int): + Optional. How much history should be fetched + for the build (default 1, -1 for all history). + dest_path (str): + Required. Where should the files be placed on + the worker. + """ + + repository: "Dependency.GitSourceRepository" = proto.Field( + proto.MESSAGE, + number=1, + message="Dependency.GitSourceRepository", + ) + revision: str = proto.Field( + proto.STRING, + number=2, + ) + recurse_submodules: bool = proto.Field( + proto.BOOL, + number=3, + ) + depth: int = proto.Field( + proto.INT64, + number=4, + ) + dest_path: str = proto.Field( + proto.STRING, + number=5, + ) + + class GitSourceRepository(proto.Message): + r"""A repository for a git source. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + url (str): + Location of the Git repository. + + This field is a member of `oneof`_ ``repotype``. + developer_connect (str): + The Developer Connect Git repository link or the url that + matches a repository link in the current project, formatted + as + ``projects/*/locations/*/connections/*/gitRepositoryLink/*`` + + This field is a member of `oneof`_ ``repotype``. + """ + + url: str = proto.Field( + proto.STRING, + number=1, + oneof="repotype", + ) + developer_connect: str = proto.Field( + proto.STRING, + number=2, + oneof="repotype", + ) + + empty: bool = proto.Field( + proto.BOOL, + number=1, + oneof="dep", + ) + git_source: GitSourceDependency = proto.Field( + proto.MESSAGE, + number=2, + oneof="dep", + message=GitSourceDependency, + ) + + +class GitConfig(proto.Message): + r"""GitConfig is a configuration for git operations. + + Attributes: + http (google.cloud.devtools.cloudbuild_v1.types.GitConfig.HttpConfig): + Configuration for HTTP related git + operations. + """ + + class HttpConfig(proto.Message): + r"""HttpConfig is a configuration for HTTP related git + operations. + + Attributes: + proxy_secret_version_name (str): + SecretVersion resource of the HTTP proxy URL. The Service + Account used in the build (either the default Service + Account or user-specified Service Account) should have + ``secretmanager.versions.access`` permissions on this + secret. The proxy URL should be in format + ``[protocol://][user[:password]@]proxyhost[:port]``. + """ + + proxy_secret_version_name: str = proto.Field( + proto.STRING, + number=1, + ) + + http: HttpConfig = proto.Field( + proto.MESSAGE, + number=1, + message=HttpConfig, + ) class Artifacts(proto.Message): @@ -2539,10 +2707,11 @@ class BuildTrigger(proto.Message): service_account (str): The service account used for all user-controlled operations including UpdateBuildTrigger, RunBuildTrigger, CreateBuild, - and CancelBuild. If no service account is set, then the - standard Cloud Build service account - ([PROJECT_NUM]@system.gserviceaccount.com) will be used - instead. Format: + and CancelBuild. If no service account is set and the legacy + Cloud Build service account + (``[PROJECT_NUM]@cloudbuild.gserviceaccount.com``) is the + default for the project then it will be used instead. + Format: ``projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT_ID_OR_EMAIL}`` repository_event_config (google.cloud.devtools.cloudbuild_v1.types.RepositoryEventConfig): The configuration of a trigger that creates a @@ -2917,29 +3086,52 @@ class PullRequestFilter(proto.Message): This field is a member of `oneof`_ ``git_ref``. comment_control (google.cloud.devtools.cloudbuild_v1.types.PullRequestFilter.CommentControl): - Configure builds to run whether a repository owner or - collaborator need to comment ``/gcbrun``. + If CommentControl is enabled, depending on the setting, + builds may not fire until a repository writer comments + ``/gcbrun`` on a pull request or ``/gcbrun`` is in the pull + request description. Only PR comments that contain + ``/gcbrun`` will trigger builds. + + If CommentControl is set to disabled, comments with + ``/gcbrun`` from a user with repository write permission or + above will still trigger builds to run. invert_regex (bool): If true, branches that do NOT match the git_ref will trigger a build. """ class CommentControl(proto.Enum): - r"""Controls behavior of Pull Request comments. + r"""Controls whether or not a ``/gcbrun`` comment is required from a + user with repository write permission or above in order to trigger + Build runs for pull requests. Pull Request update events differ + between repo types. Check repo specific guides + (`GitHub `__, + `Bitbucket `__, + `GitLab `__ + for details. Values: COMMENTS_DISABLED (0): - Do not require comments on Pull Requests - before builds are triggered. + Do not require ``/gcbrun`` comments from a user with + repository write permission or above on pull requests before + builds are triggered. Comments that contain ``/gcbrun`` will + still fire builds so this should be thought of as comments + not required. COMMENTS_ENABLED (1): - Enforce that repository owners or - collaborators must comment on Pull Requests - before builds are triggered. + Builds will only fire in response to pull requests if: + + 1. The pull request author has repository write permission + or above and ``/gcbrun`` is in the PR description. + 2. A user with repository writer permissions or above + comments ``/gcbrun`` on a pull request authored by any + user. COMMENTS_ENABLED_FOR_EXTERNAL_CONTRIBUTORS_ONLY (2): - Enforce that repository owners or - collaborators must comment on external - contributors' Pull Requests before builds are - triggered. + Builds will only fire in response to pull requests if: + + 1. The pull request author is a repository writer or above. + 2. If the author does not have write permissions, a user + with write permissions or above must comment ``/gcbrun`` + in order to fire a build. """ COMMENTS_DISABLED = 0 COMMENTS_ENABLED = 1 @@ -3212,7 +3404,7 @@ class BuildOptions(proto.Message): used by the operating system and build utilities. Also note that this is the minimum disk size that will be allocated for the build -- the build may run with a larger disk than - requested. At present, the maximum disk size is 2000GB; + requested. At present, the maximum disk size is 4000GB; builds that request more than the maximum are rejected with an error. substitution_option (google.cloud.devtools.cloudbuild_v1.types.BuildOptions.SubstitutionOption): @@ -3569,7 +3761,8 @@ class ReceiveTriggerWebhookResponse(proto.Message): class GitHubEnterpriseConfig(proto.Message): - r""" + r"""GitHubEnterpriseConfig represents a configuration for a + GitHub Enterprise server. Attributes: name (str): diff --git a/packages/google-cloud-build/noxfile.py b/packages/google-cloud-build/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-build/noxfile.py +++ b/packages/google-cloud-build/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-build/tests/unit/gapic/cloudbuild_v1/test_cloud_build.py b/packages/google-cloud-build/tests/unit/gapic/cloudbuild_v1/test_cloud_build.py index aad2528059e7..29059cc464f7 100644 --- a/packages/google-cloud-build/tests/unit/gapic/cloudbuild_v1/test_cloud_build.py +++ b/packages/google-cloud-build/tests/unit/gapic/cloudbuild_v1/test_cloud_build.py @@ -12923,7 +12923,25 @@ def test_create_build_rest_call_success(request_type): "inline": [{"kms_key_name": "kms_key_name_value", "env_map": {}}], }, "warnings": [{"text": "text_value", "priority": 1}], + "git_config": { + "http": {"proxy_secret_version_name": "proxy_secret_version_name_value"} + }, "failure_info": {"type_": 1, "detail": "detail_value"}, + "dependencies": [ + { + "empty": True, + "git_source": { + "repository": { + "url": "url_value", + "developer_connect": "developer_connect_value", + }, + "revision": "revision_value", + "recurse_submodules": True, + "depth": 533, + "dest_path": "dest_path_value", + }, + } + ], } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -13980,7 +13998,25 @@ def test_create_build_trigger_rest_call_success(request_type): "inline": [{"kms_key_name": "kms_key_name_value", "env_map": {}}], }, "warnings": [{"text": "text_value", "priority": 1}], + "git_config": { + "http": {"proxy_secret_version_name": "proxy_secret_version_name_value"} + }, "failure_info": {"type_": 1, "detail": "detail_value"}, + "dependencies": [ + { + "empty": True, + "git_source": { + "repository": { + "url": "url_value", + "developer_connect": "developer_connect_value", + }, + "revision": "revision_value", + "recurse_submodules": True, + "depth": 533, + "dest_path": "dest_path_value", + }, + } + ], }, "filename": "filename_value", "git_file_source": { @@ -14830,7 +14866,25 @@ def test_update_build_trigger_rest_call_success(request_type): "inline": [{"kms_key_name": "kms_key_name_value", "env_map": {}}], }, "warnings": [{"text": "text_value", "priority": 1}], + "git_config": { + "http": {"proxy_secret_version_name": "proxy_secret_version_name_value"} + }, "failure_info": {"type_": 1, "detail": "detail_value"}, + "dependencies": [ + { + "empty": True, + "git_source": { + "repository": { + "url": "url_value", + "developer_connect": "developer_connect_value", + }, + "revision": "revision_value", + "recurse_submodules": True, + "depth": 533, + "dest_path": "dest_path_value", + }, + } + ], }, "filename": "filename_value", "git_file_source": { @@ -17784,9 +17838,40 @@ def test_parse_github_enterprise_config_path(): assert expected == actual -def test_network_path(): +def test_git_repository_link_path(): project = "winkle" - network = "nautilus" + location = "nautilus" + connection = "scallop" + git_repository_link = "abalone" + expected = "projects/{project}/locations/{location}/connections/{connection}/gitRepositoryLinks/{git_repository_link}".format( + project=project, + location=location, + connection=connection, + git_repository_link=git_repository_link, + ) + actual = CloudBuildClient.git_repository_link_path( + project, location, connection, git_repository_link + ) + assert expected == actual + + +def test_parse_git_repository_link_path(): + expected = { + "project": "squid", + "location": "clam", + "connection": "whelk", + "git_repository_link": "octopus", + } + path = CloudBuildClient.git_repository_link_path(**expected) + + # Check that the path construction is reversible. + actual = CloudBuildClient.parse_git_repository_link_path(path) + assert expected == actual + + +def test_network_path(): + project = "oyster" + network = "nudibranch" expected = "projects/{project}/global/networks/{network}".format( project=project, network=network, @@ -17797,8 +17882,8 @@ def test_network_path(): def test_parse_network_path(): expected = { - "project": "scallop", - "network": "abalone", + "project": "cuttlefish", + "network": "mussel", } path = CloudBuildClient.network_path(**expected) @@ -17808,9 +17893,9 @@ def test_parse_network_path(): def test_network_attachment_path(): - project = "squid" - region = "clam" - networkattachment = "whelk" + project = "winkle" + region = "nautilus" + networkattachment = "scallop" expected = "projects/{project}/regions/{region}/networkAttachments/{networkattachment}".format( project=project, region=region, @@ -17824,9 +17909,9 @@ def test_network_attachment_path(): def test_parse_network_attachment_path(): expected = { - "project": "octopus", - "region": "oyster", - "networkattachment": "nudibranch", + "project": "abalone", + "region": "squid", + "networkattachment": "clam", } path = CloudBuildClient.network_attachment_path(**expected) @@ -17836,10 +17921,10 @@ def test_parse_network_attachment_path(): def test_repository_path(): - project = "cuttlefish" - location = "mussel" - connection = "winkle" - repository = "nautilus" + project = "whelk" + location = "octopus" + connection = "oyster" + repository = "nudibranch" expected = "projects/{project}/locations/{location}/connections/{connection}/repositories/{repository}".format( project=project, location=location, @@ -17852,10 +17937,10 @@ def test_repository_path(): def test_parse_repository_path(): expected = { - "project": "scallop", - "location": "abalone", - "connection": "squid", - "repository": "clam", + "project": "cuttlefish", + "location": "mussel", + "connection": "winkle", + "repository": "nautilus", } path = CloudBuildClient.repository_path(**expected) @@ -17865,9 +17950,9 @@ def test_parse_repository_path(): def test_secret_version_path(): - project = "whelk" - secret = "octopus" - version = "oyster" + project = "scallop" + secret = "abalone" + version = "squid" expected = "projects/{project}/secrets/{secret}/versions/{version}".format( project=project, secret=secret, @@ -17879,9 +17964,9 @@ def test_secret_version_path(): def test_parse_secret_version_path(): expected = { - "project": "nudibranch", - "secret": "cuttlefish", - "version": "mussel", + "project": "clam", + "secret": "whelk", + "version": "octopus", } path = CloudBuildClient.secret_version_path(**expected) @@ -17891,8 +17976,8 @@ def test_parse_secret_version_path(): def test_service_account_path(): - project = "winkle" - service_account = "nautilus" + project = "oyster" + service_account = "nudibranch" expected = "projects/{project}/serviceAccounts/{service_account}".format( project=project, service_account=service_account, @@ -17903,8 +17988,8 @@ def test_service_account_path(): def test_parse_service_account_path(): expected = { - "project": "scallop", - "service_account": "abalone", + "project": "cuttlefish", + "service_account": "mussel", } path = CloudBuildClient.service_account_path(**expected) @@ -17914,8 +17999,8 @@ def test_parse_service_account_path(): def test_subscription_path(): - project = "squid" - subscription = "clam" + project = "winkle" + subscription = "nautilus" expected = "projects/{project}/subscriptions/{subscription}".format( project=project, subscription=subscription, @@ -17926,8 +18011,8 @@ def test_subscription_path(): def test_parse_subscription_path(): expected = { - "project": "whelk", - "subscription": "octopus", + "project": "scallop", + "subscription": "abalone", } path = CloudBuildClient.subscription_path(**expected) @@ -17937,8 +18022,8 @@ def test_parse_subscription_path(): def test_topic_path(): - project = "oyster" - topic = "nudibranch" + project = "squid" + topic = "clam" expected = "projects/{project}/topics/{topic}".format( project=project, topic=topic, @@ -17949,8 +18034,8 @@ def test_topic_path(): def test_parse_topic_path(): expected = { - "project": "cuttlefish", - "topic": "mussel", + "project": "whelk", + "topic": "octopus", } path = CloudBuildClient.topic_path(**expected) @@ -17960,9 +18045,9 @@ def test_parse_topic_path(): def test_worker_pool_path(): - project = "winkle" - location = "nautilus" - worker_pool = "scallop" + project = "oyster" + location = "nudibranch" + worker_pool = "cuttlefish" expected = ( "projects/{project}/locations/{location}/workerPools/{worker_pool}".format( project=project, @@ -17976,9 +18061,9 @@ def test_worker_pool_path(): def test_parse_worker_pool_path(): expected = { - "project": "abalone", - "location": "squid", - "worker_pool": "clam", + "project": "mussel", + "location": "winkle", + "worker_pool": "nautilus", } path = CloudBuildClient.worker_pool_path(**expected) @@ -17988,7 +18073,7 @@ def test_parse_worker_pool_path(): def test_common_billing_account_path(): - billing_account = "whelk" + billing_account = "scallop" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -17998,7 +18083,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "octopus", + "billing_account": "abalone", } path = CloudBuildClient.common_billing_account_path(**expected) @@ -18008,7 +18093,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "oyster" + folder = "squid" expected = "folders/{folder}".format( folder=folder, ) @@ -18018,7 +18103,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "nudibranch", + "folder": "clam", } path = CloudBuildClient.common_folder_path(**expected) @@ -18028,7 +18113,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "cuttlefish" + organization = "whelk" expected = "organizations/{organization}".format( organization=organization, ) @@ -18038,7 +18123,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "mussel", + "organization": "octopus", } path = CloudBuildClient.common_organization_path(**expected) @@ -18048,7 +18133,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "winkle" + project = "oyster" expected = "projects/{project}".format( project=project, ) @@ -18058,7 +18143,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nautilus", + "project": "nudibranch", } path = CloudBuildClient.common_project_path(**expected) @@ -18068,8 +18153,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "scallop" - location = "abalone" + project = "cuttlefish" + location = "mussel" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -18080,8 +18165,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "squid", - "location": "clam", + "project": "winkle", + "location": "nautilus", } path = CloudBuildClient.common_location_path(**expected) From 1ae6890470d6050c5cadd81246bbb26d8146af9d Mon Sep 17 00:00:00 2001 From: yoshi-code-bot <70984784+yoshi-code-bot@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:07:07 -0800 Subject: [PATCH 09/13] chore: Update the root changelog (#13534) Update the root changelog --- CHANGELOG.md | 336 +++++++++++++++++++++++++-------------------------- 1 file changed, 168 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f82b7120196..48db887c98e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,133 +2,133 @@ Please refer to each API's `CHANGELOG.md` file under the `packages/` directory Changelogs ----- -- [google-ads-admanager==0.2.3](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ads-admanager/CHANGELOG.md) -- [google-ads-marketingplatform-admin==0.1.3](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ads-marketingplatform-admin/CHANGELOG.md) -- [google-ai-generativelanguage==0.6.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ai-generativelanguage/CHANGELOG.md) -- [google-analytics-admin==0.23.3](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-admin/CHANGELOG.md) -- [google-analytics-data==0.18.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-data/CHANGELOG.md) -- [google-apps-card==0.1.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-card/CHANGELOG.md) -- [google-apps-chat==0.2.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-chat/CHANGELOG.md) -- [google-apps-events-subscriptions==0.1.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-events-subscriptions/CHANGELOG.md) -- [google-apps-meet==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-meet/CHANGELOG.md) -- [google-apps-script-type==0.3.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-script-type/CHANGELOG.md) -- [google-area120-tables==0.11.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-area120-tables/CHANGELOG.md) -- [google-cloud-access-approval==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-access-approval/CHANGELOG.md) +- [google-ads-admanager==0.2.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ads-admanager/CHANGELOG.md) +- [google-ads-marketingplatform-admin==0.1.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ads-marketingplatform-admin/CHANGELOG.md) +- [google-ai-generativelanguage==0.6.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-ai-generativelanguage/CHANGELOG.md) +- [google-analytics-admin==0.23.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-admin/CHANGELOG.md) +- [google-analytics-data==0.18.17](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-data/CHANGELOG.md) +- [google-apps-card==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-card/CHANGELOG.md) +- [google-apps-chat==0.2.2](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-chat/CHANGELOG.md) +- [google-apps-events-subscriptions==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-events-subscriptions/CHANGELOG.md) +- [google-apps-meet==0.1.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-meet/CHANGELOG.md) +- [google-apps-script-type==0.3.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-script-type/CHANGELOG.md) +- [google-area120-tables==0.11.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-area120-tables/CHANGELOG.md) +- [google-cloud-access-approval==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-access-approval/CHANGELOG.md) - [google-cloud-access-context-manager==0.2.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-access-context-manager/CHANGELOG.md) -- [google-cloud-advisorynotifications==0.3.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-advisorynotifications/CHANGELOG.md) -- [google-cloud-alloydb-connectors==0.1.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-alloydb-connectors/CHANGELOG.md) -- [google-cloud-alloydb==0.4.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-alloydb/CHANGELOG.md) -- [google-cloud-api-gateway==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-api-gateway/CHANGELOG.md) -- [google-cloud-api-keys==0.5.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-api-keys/CHANGELOG.md) -- [google-cloud-apigee-connect==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apigee-connect/CHANGELOG.md) -- [google-cloud-apigee-registry==0.6.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apigee-registry/CHANGELOG.md) -- [google-cloud-apihub==0.2.3](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apihub/CHANGELOG.md) -- [google-cloud-appengine-admin==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-appengine-admin/CHANGELOG.md) -- [google-cloud-appengine-logging==1.5.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-appengine-logging/CHANGELOG.md) -- [google-cloud-apphub==0.1.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apphub/CHANGELOG.md) -- [google-cloud-artifact-registry==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-artifact-registry/CHANGELOG.md) -- [google-cloud-asset==3.28.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-asset/CHANGELOG.md) -- [google-cloud-assured-workloads==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-assured-workloads/CHANGELOG.md) +- [google-cloud-advisorynotifications==0.3.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-advisorynotifications/CHANGELOG.md) +- [google-cloud-alloydb-connectors==0.1.8](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-alloydb-connectors/CHANGELOG.md) +- [google-cloud-alloydb==0.4.2](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-alloydb/CHANGELOG.md) +- [google-cloud-api-gateway==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-api-gateway/CHANGELOG.md) +- [google-cloud-api-keys==0.5.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-api-keys/CHANGELOG.md) +- [google-cloud-apigee-connect==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apigee-connect/CHANGELOG.md) +- [google-cloud-apigee-registry==0.6.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apigee-registry/CHANGELOG.md) +- [google-cloud-apihub==0.2.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apihub/CHANGELOG.md) +- [google-cloud-appengine-admin==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-appengine-admin/CHANGELOG.md) +- [google-cloud-appengine-logging==1.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-appengine-logging/CHANGELOG.md) +- [google-cloud-apphub==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-apphub/CHANGELOG.md) +- [google-cloud-artifact-registry==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-artifact-registry/CHANGELOG.md) +- [google-cloud-asset==3.29.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-asset/CHANGELOG.md) +- [google-cloud-assured-workloads==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-assured-workloads/CHANGELOG.md) - [google-cloud-audit-log==0.3.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-audit-log/CHANGELOG.md) -- [google-cloud-automl==2.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-automl/CHANGELOG.md) -- [google-cloud-backupdr==0.2.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-backupdr/CHANGELOG.md) -- [google-cloud-bare-metal-solution==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bare-metal-solution/CHANGELOG.md) -- [google-cloud-batch==0.17.33](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-batch/CHANGELOG.md) -- [google-cloud-beyondcorp-appconnections==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md) -- [google-cloud-beyondcorp-appconnectors==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md) -- [google-cloud-beyondcorp-appgateways==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md) -- [google-cloud-beyondcorp-clientconnectorservices==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md) -- [google-cloud-beyondcorp-clientgateways==0.4.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md) -- [google-cloud-bigquery-analyticshub==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md) -- [google-cloud-bigquery-biglake==0.4.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-biglake/CHANGELOG.md) -- [google-cloud-bigquery-connection==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-connection/CHANGELOG.md) -- [google-cloud-bigquery-data-exchange==0.5.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md) -- [google-cloud-bigquery-datapolicies==0.6.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md) -- [google-cloud-bigquery-datatransfer==3.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datatransfer/CHANGELOG.md) -- [google-cloud-bigquery-logging==1.5.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-logging/CHANGELOG.md) -- [google-cloud-bigquery-migration==0.11.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-migration/CHANGELOG.md) -- [google-cloud-bigquery-reservation==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-reservation/CHANGELOG.md) -- [google-cloud-billing-budgets==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing-budgets/CHANGELOG.md) -- [google-cloud-billing==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing/CHANGELOG.md) -- [google-cloud-binary-authorization==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-binary-authorization/CHANGELOG.md) -- [google-cloud-build==3.29.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-build/CHANGELOG.md) -- [google-cloud-certificate-manager==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-certificate-manager/CHANGELOG.md) -- [google-cloud-channel==1.21.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-channel/CHANGELOG.md) -- [google-cloud-cloudcontrolspartner==0.2.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-cloudcontrolspartner/CHANGELOG.md) -- [google-cloud-commerce-consumer-procurement==0.1.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-commerce-consumer-procurement/CHANGELOG.md) -- [google-cloud-common==1.4.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-common/CHANGELOG.md) -- [google-cloud-compute==1.24.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-compute/CHANGELOG.md) -- [google-cloud-confidentialcomputing==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-confidentialcomputing/CHANGELOG.md) -- [google-cloud-config==0.1.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-config/CHANGELOG.md) -- [google-cloud-contact-center-insights==1.22.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contact-center-insights/CHANGELOG.md) -- [google-cloud-container==2.55.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-container/CHANGELOG.md) -- [google-cloud-containeranalysis==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-containeranalysis/CHANGELOG.md) -- [google-cloud-contentwarehouse==0.7.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contentwarehouse/CHANGELOG.md) -- [google-cloud-data-fusion==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-data-fusion/CHANGELOG.md) -- [google-cloud-data-qna==0.10.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-data-qna/CHANGELOG.md) -- [google-cloud-datacatalog-lineage==0.3.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datacatalog-lineage/CHANGELOG.md) -- [google-cloud-datacatalog==3.24.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datacatalog/CHANGELOG.md) -- [google-cloud-dataflow-client==0.8.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataflow-client/CHANGELOG.md) -- [google-cloud-dataform==0.5.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataform/CHANGELOG.md) -- [google-cloud-datalabeling==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datalabeling/CHANGELOG.md) -- [google-cloud-dataplex==2.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataplex/CHANGELOG.md) -- [google-cloud-dataproc-metastore==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc-metastore/CHANGELOG.md) -- [google-cloud-dataproc==5.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc/CHANGELOG.md) -- [google-cloud-datastream==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datastream/CHANGELOG.md) -- [google-cloud-deploy==2.5.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-deploy/CHANGELOG.md) -- [google-cloud-developerconnect==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-developerconnect/CHANGELOG.md) -- [google-cloud-dialogflow-cx==1.38.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dialogflow-cx/CHANGELOG.md) -- [google-cloud-dialogflow==2.38.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dialogflow/CHANGELOG.md) -- [google-cloud-discoveryengine==0.13.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-discoveryengine/CHANGELOG.md) -- [google-cloud-dlp==3.26.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dlp/CHANGELOG.md) -- [google-cloud-dms==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dms/CHANGELOG.md) -- [google-cloud-documentai==3.1.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-documentai/CHANGELOG.md) -- [google-cloud-domains==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-domains/CHANGELOG.md) -- [google-cloud-edgecontainer==0.5.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-edgecontainer/CHANGELOG.md) -- [google-cloud-edgenetwork==0.1.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-edgenetwork/CHANGELOG.md) -- [google-cloud-enterpriseknowledgegraph==0.3.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-enterpriseknowledgegraph/CHANGELOG.md) -- [google-cloud-essential-contacts==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-essential-contacts/CHANGELOG.md) -- [google-cloud-eventarc-publishing==0.6.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-eventarc-publishing/CHANGELOG.md) -- [google-cloud-eventarc==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-eventarc/CHANGELOG.md) -- [google-cloud-filestore==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-filestore/CHANGELOG.md) -- [google-cloud-functions==1.19.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-functions/CHANGELOG.md) -- [google-cloud-gdchardwaremanagement==0.1.9](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gdchardwaremanagement/CHANGELOG.md) -- [google-cloud-gke-backup==0.5.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-backup/CHANGELOG.md) -- [google-cloud-gke-connect-gateway==0.10.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-connect-gateway/CHANGELOG.md) -- [google-cloud-gke-hub==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-hub/CHANGELOG.md) -- [google-cloud-gke-multicloud==0.6.18](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-multicloud/CHANGELOG.md) -- [google-cloud-gsuiteaddons==0.3.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gsuiteaddons/CHANGELOG.md) +- [google-cloud-automl==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-automl/CHANGELOG.md) +- [google-cloud-backupdr==0.2.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-backupdr/CHANGELOG.md) +- [google-cloud-bare-metal-solution==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bare-metal-solution/CHANGELOG.md) +- [google-cloud-batch==0.17.34](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-batch/CHANGELOG.md) +- [google-cloud-beyondcorp-appconnections==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md) +- [google-cloud-beyondcorp-appconnectors==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md) +- [google-cloud-beyondcorp-appgateways==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md) +- [google-cloud-beyondcorp-clientconnectorservices==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md) +- [google-cloud-beyondcorp-clientgateways==0.4.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md) +- [google-cloud-bigquery-analyticshub==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md) +- [google-cloud-bigquery-biglake==0.4.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-biglake/CHANGELOG.md) +- [google-cloud-bigquery-connection==1.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-connection/CHANGELOG.md) +- [google-cloud-bigquery-data-exchange==0.5.17](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md) +- [google-cloud-bigquery-datapolicies==0.6.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md) +- [google-cloud-bigquery-datatransfer==3.19.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-datatransfer/CHANGELOG.md) +- [google-cloud-bigquery-logging==1.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-logging/CHANGELOG.md) +- [google-cloud-bigquery-migration==0.11.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-migration/CHANGELOG.md) +- [google-cloud-bigquery-reservation==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-bigquery-reservation/CHANGELOG.md) +- [google-cloud-billing-budgets==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing-budgets/CHANGELOG.md) +- [google-cloud-billing==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-billing/CHANGELOG.md) +- [google-cloud-binary-authorization==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-binary-authorization/CHANGELOG.md) +- [google-cloud-build==3.30.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-build/CHANGELOG.md) +- [google-cloud-certificate-manager==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-certificate-manager/CHANGELOG.md) +- [google-cloud-channel==1.22.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-channel/CHANGELOG.md) +- [google-cloud-cloudcontrolspartner==0.2.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-cloudcontrolspartner/CHANGELOG.md) +- [google-cloud-commerce-consumer-procurement==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-commerce-consumer-procurement/CHANGELOG.md) +- [google-cloud-common==1.5.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-common/CHANGELOG.md) +- [google-cloud-compute==1.25.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-compute/CHANGELOG.md) +- [google-cloud-confidentialcomputing==0.4.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-confidentialcomputing/CHANGELOG.md) +- [google-cloud-config==0.1.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-config/CHANGELOG.md) +- [google-cloud-contact-center-insights==1.23.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contact-center-insights/CHANGELOG.md) +- [google-cloud-container==2.56.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-container/CHANGELOG.md) +- [google-cloud-containeranalysis==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-containeranalysis/CHANGELOG.md) +- [google-cloud-contentwarehouse==0.7.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-contentwarehouse/CHANGELOG.md) +- [google-cloud-data-fusion==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-data-fusion/CHANGELOG.md) +- [google-cloud-data-qna==0.10.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-data-qna/CHANGELOG.md) +- [google-cloud-datacatalog-lineage==0.3.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datacatalog-lineage/CHANGELOG.md) +- [google-cloud-datacatalog==3.25.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datacatalog/CHANGELOG.md) +- [google-cloud-dataflow-client==0.8.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataflow-client/CHANGELOG.md) +- [google-cloud-dataform==0.5.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataform/CHANGELOG.md) +- [google-cloud-datalabeling==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datalabeling/CHANGELOG.md) +- [google-cloud-dataplex==2.7.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataplex/CHANGELOG.md) +- [google-cloud-dataproc-metastore==1.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc-metastore/CHANGELOG.md) +- [google-cloud-dataproc==5.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dataproc/CHANGELOG.md) +- [google-cloud-datastream==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-datastream/CHANGELOG.md) +- [google-cloud-deploy==2.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-deploy/CHANGELOG.md) +- [google-cloud-developerconnect==0.1.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-developerconnect/CHANGELOG.md) +- [google-cloud-dialogflow-cx==1.39.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dialogflow-cx/CHANGELOG.md) +- [google-cloud-dialogflow==2.39.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dialogflow/CHANGELOG.md) +- [google-cloud-discoveryengine==0.13.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-discoveryengine/CHANGELOG.md) +- [google-cloud-dlp==3.27.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dlp/CHANGELOG.md) +- [google-cloud-dms==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-dms/CHANGELOG.md) +- [google-cloud-documentai==3.2.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-documentai/CHANGELOG.md) +- [google-cloud-domains==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-domains/CHANGELOG.md) +- [google-cloud-edgecontainer==0.5.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-edgecontainer/CHANGELOG.md) +- [google-cloud-edgenetwork==0.1.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-edgenetwork/CHANGELOG.md) +- [google-cloud-enterpriseknowledgegraph==0.3.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-enterpriseknowledgegraph/CHANGELOG.md) +- [google-cloud-essential-contacts==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-essential-contacts/CHANGELOG.md) +- [google-cloud-eventarc-publishing==0.6.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-eventarc-publishing/CHANGELOG.md) +- [google-cloud-eventarc==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-eventarc/CHANGELOG.md) +- [google-cloud-filestore==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-filestore/CHANGELOG.md) +- [google-cloud-functions==1.20.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-functions/CHANGELOG.md) +- [google-cloud-gdchardwaremanagement==0.1.10](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gdchardwaremanagement/CHANGELOG.md) +- [google-cloud-gke-backup==0.5.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-backup/CHANGELOG.md) +- [google-cloud-gke-connect-gateway==0.10.2](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-connect-gateway/CHANGELOG.md) +- [google-cloud-gke-hub==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-hub/CHANGELOG.md) +- [google-cloud-gke-multicloud==0.6.19](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gke-multicloud/CHANGELOG.md) +- [google-cloud-gsuiteaddons==0.3.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-gsuiteaddons/CHANGELOG.md) - [google-cloud-iam-logging==1.4.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iam-logging/CHANGELOG.md) -- [google-cloud-iam==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iam/CHANGELOG.md) -- [google-cloud-iap==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iap/CHANGELOG.md) -- [google-cloud-ids==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-ids/CHANGELOG.md) -- [google-cloud-kms-inventory==0.2.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms-inventory/CHANGELOG.md) -- [google-cloud-kms==3.2.2](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms/CHANGELOG.md) -- [google-cloud-language==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-language/CHANGELOG.md) -- [google-cloud-life-sciences==0.9.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-life-sciences/CHANGELOG.md) -- [google-cloud-managed-identities==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-managed-identities/CHANGELOG.md) -- [google-cloud-managedkafka==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-managedkafka/CHANGELOG.md) -- [google-cloud-media-translation==0.11.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-media-translation/CHANGELOG.md) -- [google-cloud-memcache==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-memcache/CHANGELOG.md) -- [google-cloud-memorystore==0.1.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-memorystore/CHANGELOG.md) -- [google-cloud-migrationcenter==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-migrationcenter/CHANGELOG.md) -- [google-cloud-modelarmor==0.1.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-modelarmor/CHANGELOG.md) -- [google-cloud-monitoring-dashboards==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring-dashboards/CHANGELOG.md) -- [google-cloud-monitoring-metrics-scopes==1.8.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring-metrics-scopes/CHANGELOG.md) -- [google-cloud-monitoring==2.26.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring/CHANGELOG.md) -- [google-cloud-netapp==0.3.18](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-netapp/CHANGELOG.md) -- [google-cloud-network-connectivity==2.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-connectivity/CHANGELOG.md) -- [google-cloud-network-management==1.24.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-management/CHANGELOG.md) -- [google-cloud-network-security==0.9.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-security/CHANGELOG.md) -- [google-cloud-network-services==0.5.17](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-services/CHANGELOG.md) -- [google-cloud-notebooks==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-notebooks/CHANGELOG.md) -- [google-cloud-optimization==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-optimization/CHANGELOG.md) -- [google-cloud-oracledatabase==0.1.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-oracledatabase/CHANGELOG.md) -- [google-cloud-orchestration-airflow==1.16.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-orchestration-airflow/CHANGELOG.md) -- [google-cloud-org-policy==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-org-policy/CHANGELOG.md) -- [google-cloud-os-config==1.19.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-os-config/CHANGELOG.md) -- [google-cloud-os-login==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-os-login/CHANGELOG.md) -- [google-cloud-parallelstore==0.2.9](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-parallelstore/CHANGELOG.md) +- [google-cloud-iam==2.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iam/CHANGELOG.md) +- [google-cloud-iap==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-iap/CHANGELOG.md) +- [google-cloud-ids==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-ids/CHANGELOG.md) +- [google-cloud-kms-inventory==0.2.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms-inventory/CHANGELOG.md) +- [google-cloud-kms==3.3.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-kms/CHANGELOG.md) +- [google-cloud-language==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-language/CHANGELOG.md) +- [google-cloud-life-sciences==0.9.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-life-sciences/CHANGELOG.md) +- [google-cloud-managed-identities==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-managed-identities/CHANGELOG.md) +- [google-cloud-managedkafka==0.1.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-managedkafka/CHANGELOG.md) +- [google-cloud-media-translation==0.11.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-media-translation/CHANGELOG.md) +- [google-cloud-memcache==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-memcache/CHANGELOG.md) +- [google-cloud-memorystore==0.1.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-memorystore/CHANGELOG.md) +- [google-cloud-migrationcenter==0.1.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-migrationcenter/CHANGELOG.md) +- [google-cloud-modelarmor==0.1.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-modelarmor/CHANGELOG.md) +- [google-cloud-monitoring-dashboards==2.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring-dashboards/CHANGELOG.md) +- [google-cloud-monitoring-metrics-scopes==1.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring-metrics-scopes/CHANGELOG.md) +- [google-cloud-monitoring==2.27.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-monitoring/CHANGELOG.md) +- [google-cloud-netapp==0.3.19](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-netapp/CHANGELOG.md) +- [google-cloud-network-connectivity==2.7.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-connectivity/CHANGELOG.md) +- [google-cloud-network-management==1.25.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-management/CHANGELOG.md) +- [google-cloud-network-security==0.9.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-security/CHANGELOG.md) +- [google-cloud-network-services==0.5.18](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-network-services/CHANGELOG.md) +- [google-cloud-notebooks==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-notebooks/CHANGELOG.md) +- [google-cloud-optimization==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-optimization/CHANGELOG.md) +- [google-cloud-oracledatabase==0.1.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-oracledatabase/CHANGELOG.md) +- [google-cloud-orchestration-airflow==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-orchestration-airflow/CHANGELOG.md) +- [google-cloud-org-policy==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-org-policy/CHANGELOG.md) +- [google-cloud-os-config==1.20.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-os-config/CHANGELOG.md) +- [google-cloud-os-login==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-os-login/CHANGELOG.md) +- [google-cloud-parallelstore==0.2.10](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-parallelstore/CHANGELOG.md) - [google-cloud-parametermanager==0.1.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-parametermanager/CHANGELOG.md) - [google-cloud-phishing-protection==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-phishing-protection/CHANGELOG.md) - [google-cloud-policy-troubleshooter==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-policy-troubleshooter/CHANGELOG.md) @@ -148,51 +148,51 @@ Changelogs - [google-cloud-resource-manager==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-resource-manager/CHANGELOG.md) - [google-cloud-resource-settings==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-resource-settings/CHANGELOG.md) - [google-cloud-retail==1.24.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-retail/CHANGELOG.md) -- [google-cloud-run==0.10.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-run/CHANGELOG.md) +- [google-cloud-run==0.10.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-run/CHANGELOG.md) - [google-cloud-scheduler==2.15.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-scheduler/CHANGELOG.md) -- [google-cloud-secret-manager==2.22.1](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-secret-manager/CHANGELOG.md) -- [google-cloud-securesourcemanager==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securesourcemanager/CHANGELOG.md) -- [google-cloud-securitycenter==1.36.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycenter/CHANGELOG.md) -- [google-cloud-securitycentermanagement==0.1.18](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycentermanagement/CHANGELOG.md) -- [google-cloud-service-control==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-control/CHANGELOG.md) -- [google-cloud-service-directory==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-directory/CHANGELOG.md) -- [google-cloud-service-management==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-management/CHANGELOG.md) -- [google-cloud-service-usage==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-usage/CHANGELOG.md) -- [google-cloud-servicehealth==0.1.10](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-servicehealth/CHANGELOG.md) -- [google-cloud-shell==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-shell/CHANGELOG.md) -- [google-cloud-source-context==1.6.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-source-context/CHANGELOG.md) -- [google-cloud-speech==2.30.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-speech/CHANGELOG.md) -- [google-cloud-storage-control==1.2.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storage-control/CHANGELOG.md) -- [google-cloud-storage-transfer==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storage-transfer/CHANGELOG.md) -- [google-cloud-storageinsights==0.1.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storageinsights/CHANGELOG.md) -- [google-cloud-support==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-support/CHANGELOG.md) -- [google-cloud-talent==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-talent/CHANGELOG.md) -- [google-cloud-tasks==2.18.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-tasks/CHANGELOG.md) -- [google-cloud-telcoautomation==0.2.8](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-telcoautomation/CHANGELOG.md) -- [google-cloud-texttospeech==2.24.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-texttospeech/CHANGELOG.md) -- [google-cloud-tpu==1.22.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-tpu/CHANGELOG.md) -- [google-cloud-trace==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-trace/CHANGELOG.md) -- [google-cloud-translate==3.19.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-translate/CHANGELOG.md) -- [google-cloud-video-live-stream==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-live-stream/CHANGELOG.md) -- [google-cloud-video-stitcher==0.7.15](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-stitcher/CHANGELOG.md) -- [google-cloud-video-transcoder==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-transcoder/CHANGELOG.md) -- [google-cloud-videointelligence==2.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-videointelligence/CHANGELOG.md) -- [google-cloud-vision==3.9.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vision/CHANGELOG.md) -- [google-cloud-visionai==0.1.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-visionai/CHANGELOG.md) -- [google-cloud-vm-migration==1.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vm-migration/CHANGELOG.md) -- [google-cloud-vmwareengine==1.7.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vmwareengine/CHANGELOG.md) -- [google-cloud-vpc-access==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vpc-access/CHANGELOG.md) -- [google-cloud-webrisk==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-webrisk/CHANGELOG.md) -- [google-cloud-websecurityscanner==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-websecurityscanner/CHANGELOG.md) -- [google-cloud-workflows==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-workflows/CHANGELOG.md) -- [google-cloud-workstations==0.5.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-workstations/CHANGELOG.md) -- [google-geo-type==0.3.10](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-geo-type/CHANGELOG.md) -- [google-maps-addressvalidation==0.3.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-addressvalidation/CHANGELOG.md) -- [google-maps-areainsights==0.1.3](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-areainsights/CHANGELOG.md) -- [google-maps-fleetengine-delivery==0.2.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-fleetengine-delivery/CHANGELOG.md) -- [google-maps-fleetengine==0.2.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-fleetengine/CHANGELOG.md) +- [google-cloud-secret-manager==2.23.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-secret-manager/CHANGELOG.md) +- [google-cloud-securesourcemanager==0.1.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securesourcemanager/CHANGELOG.md) +- [google-cloud-securitycenter==1.37.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycenter/CHANGELOG.md) +- [google-cloud-securitycentermanagement==0.1.19](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-securitycentermanagement/CHANGELOG.md) +- [google-cloud-service-control==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-control/CHANGELOG.md) +- [google-cloud-service-directory==1.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-directory/CHANGELOG.md) +- [google-cloud-service-management==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-management/CHANGELOG.md) +- [google-cloud-service-usage==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-service-usage/CHANGELOG.md) +- [google-cloud-servicehealth==0.1.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-servicehealth/CHANGELOG.md) +- [google-cloud-shell==1.12.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-shell/CHANGELOG.md) +- [google-cloud-source-context==1.7.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-source-context/CHANGELOG.md) +- [google-cloud-speech==2.31.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-speech/CHANGELOG.md) +- [google-cloud-storage-control==1.3.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storage-control/CHANGELOG.md) +- [google-cloud-storage-transfer==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storage-transfer/CHANGELOG.md) +- [google-cloud-storageinsights==0.1.14](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-storageinsights/CHANGELOG.md) +- [google-cloud-support==0.1.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-support/CHANGELOG.md) +- [google-cloud-talent==2.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-talent/CHANGELOG.md) +- [google-cloud-tasks==2.19.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-tasks/CHANGELOG.md) +- [google-cloud-telcoautomation==0.2.9](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-telcoautomation/CHANGELOG.md) +- [google-cloud-texttospeech==2.25.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-texttospeech/CHANGELOG.md) +- [google-cloud-tpu==1.23.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-tpu/CHANGELOG.md) +- [google-cloud-trace==1.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-trace/CHANGELOG.md) +- [google-cloud-translate==3.20.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-translate/CHANGELOG.md) +- [google-cloud-video-live-stream==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-live-stream/CHANGELOG.md) +- [google-cloud-video-stitcher==0.7.16](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-stitcher/CHANGELOG.md) +- [google-cloud-video-transcoder==1.15.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-video-transcoder/CHANGELOG.md) +- [google-cloud-videointelligence==2.16.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-videointelligence/CHANGELOG.md) +- [google-cloud-vision==3.10.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vision/CHANGELOG.md) +- [google-cloud-visionai==0.1.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-visionai/CHANGELOG.md) +- [google-cloud-vm-migration==1.11.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vm-migration/CHANGELOG.md) +- [google-cloud-vmwareengine==1.8.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vmwareengine/CHANGELOG.md) +- [google-cloud-vpc-access==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-vpc-access/CHANGELOG.md) +- [google-cloud-webrisk==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-webrisk/CHANGELOG.md) +- [google-cloud-websecurityscanner==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-websecurityscanner/CHANGELOG.md) +- [google-cloud-workflows==1.17.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-workflows/CHANGELOG.md) +- [google-cloud-workstations==0.5.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-workstations/CHANGELOG.md) +- [google-geo-type==0.3.11](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-geo-type/CHANGELOG.md) +- [google-maps-addressvalidation==0.3.17](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-addressvalidation/CHANGELOG.md) +- [google-maps-areainsights==0.1.4](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-areainsights/CHANGELOG.md) +- [google-maps-fleetengine-delivery==0.2.8](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-fleetengine-delivery/CHANGELOG.md) +- [google-maps-fleetengine==0.2.6](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-fleetengine/CHANGELOG.md) - [google-maps-mapsplatformdatasets==0.4.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-mapsplatformdatasets/CHANGELOG.md) -- [google-maps-places==0.1.22](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-places/CHANGELOG.md) +- [google-maps-places==0.1.23](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-places/CHANGELOG.md) - [google-maps-routeoptimization==0.1.7](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-routeoptimization/CHANGELOG.md) - [google-maps-routing==0.6.13](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-routing/CHANGELOG.md) - [google-maps-solar==0.1.5](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-maps-solar/CHANGELOG.md) @@ -209,7 +209,7 @@ Changelogs - [google-shopping-merchant-reports==0.1.12](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-shopping-merchant-reports/CHANGELOG.md) - [google-shopping-merchant-reviews==0.1.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-shopping-merchant-reviews/CHANGELOG.md) - [google-shopping-type==0.1.9](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-shopping-type/CHANGELOG.md) -- [googleapis-common-protos==1.66.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/googleapis-common-protos/CHANGELOG.md) +- [googleapis-common-protos==1.67.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/googleapis-common-protos/CHANGELOG.md) - [grafeas==1.13.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/grafeas/CHANGELOG.md) - [grpc-google-iam-v1==0.14.0](https://github.com/googleapis/google-cloud-python/tree/main/packages/grpc-google-iam-v1/CHANGELOG.md) From 5dabf5556d505f55171344fd7c95384b8478e453 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Tue, 18 Feb 2025 12:35:39 -0500 Subject: [PATCH 10/13] fix: allow google-cloud-storage 3.x (#13535) See https://pypi.org/project/google-cloud-storage/3.0.0/ --- packages/google-cloud-automl/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-cloud-automl/setup.py b/packages/google-cloud-automl/setup.py index 15d0a07fa1cb..5c7fdfff2b30 100644 --- a/packages/google-cloud-automl/setup.py +++ b/packages/google-cloud-automl/setup.py @@ -50,7 +50,7 @@ extras = { "libcst": "libcst >= 0.2.5", "pandas": ["pandas>=1.0.5"], - "storage": ["google-cloud-storage >=1.18.0, <3.0.0dev"], + "storage": ["google-cloud-storage >=1.18.0, <4.0.0dev"], } url = "https://github.com/googleapis/google-cloud-python/tree/main/packages/google-cloud-automl" From c8e0760e8088950c62279335216ad1d17716ce59 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:40:04 +0500 Subject: [PATCH 11/13] feat: [Many APIs] Add REST Interceptors which support reading metadata (#13500) BEGIN_COMMIT_OVERRIDE feat: Add REST Interceptors which support reading metadata feat: Add support for reading selective GAPIC generation methods from service YAML chore: Update gapic-generator-python to v1.22.0 END_COMMIT_OVERRIDE - [ ] Regenerate this pull request now. feat: Add support for reading selective GAPIC generation methods from service YAML chore: Update gapic-generator-python to v1.22.0 PiperOrigin-RevId: 724026024 Source-Link: https://github.com/googleapis/googleapis/commit/ad9963857109513e77eed153a66264481789109f Source-Link: https://github.com/googleapis/googleapis-gen/commit/e291c4dd1d670eda19998de76f967e1603a48993 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBhcmFtZXRlcm1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBoaXNoaW5nLXByb3RlY3Rpb24vLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeS10cm91Ymxlc2hvb3Rlci8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXNpbXVsYXRvci8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXRyb3VibGVzaG9vdGVyLWlhbS8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZhdGUtY2EvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZhdGUtY2F0YWxvZy8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZpbGVnZWRhY2Nlc3NtYW5hZ2VyLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXB1YmxpYy1jYS8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXF1b3Rhcy8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJhcGlkbWlncmF0aW9uYXNzZXNzbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlY2FwdGNoYS1lbnRlcnByaXNlLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlY29tbWVuZGF0aW9ucy1haS8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlY29tbWVuZGVyLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlZGlzLWNsdXN0ZXIvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlZGlzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlc291cmNlLW1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6ImUyOTFjNGRkMWQ2NzBlZGExOTk5OGRlNzZmOTY3ZTE2MDNhNDg5OTMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlc291cmNlLXNldHRpbmdzLy5Pd2xCb3QueWFtbCIsImgiOiJlMjkxYzRkZDFkNjcwZWRhMTk5OThkZTc2Zjk2N2UxNjAzYTQ4OTkzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJldGFpbC8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNjaGVkdWxlci8uT3dsQm90LnlhbWwiLCJoIjoiZTI5MWM0ZGQxZDY3MGVkYTE5OTk4ZGU3NmY5NjdlMTYwM2E0ODk5MyJ9 --------- Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .../README.rst | 4 +- .../cloud/phishingprotection/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../client.py | 29 ++ .../transports/rest.py | 34 +- .../noxfile.py | 81 +++- ...ogle.cloud.phishingprotection.v1beta1.json | 2 +- ...st_phishing_protection_service_v1_beta1.py | 59 +++ .../google-cloud-private-catalog/README.rst | 4 +- .../cloud/privatecatalog/gapic_version.py | 2 +- .../privatecatalog_v1beta1/gapic_version.py | 2 +- .../services/private_catalog/client.py | 29 ++ .../private_catalog/transports/rest.py | 99 +++- .../google-cloud-private-catalog/noxfile.py | 81 +++- ...a_google.cloud.privatecatalog.v1beta1.json | 2 +- .../test_private_catalog.py | 74 +++ .../README.rst | 4 +- .../privilegedaccessmanager/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../privileged_access_manager/client.py | 117 +++-- .../transports/rest.py | 451 +++++++++++++++-- .../noxfile.py | 81 +++- ...ogle.cloud.privilegedaccessmanager.v1.json | 2 +- .../test_privileged_access_manager.py | 152 ++++++ packages/google-cloud-public-ca/README.rst | 4 +- .../cloud/security/publicca/gapic_version.py | 2 +- .../security/publicca_v1/gapic_version.py | 2 +- .../client.py | 29 ++ .../transports/rest.py | 31 +- .../publicca_v1beta1/gapic_version.py | 2 +- .../client.py | 29 ++ .../transports/rest.py | 31 +- packages/google-cloud-public-ca/noxfile.py | 81 +++- ...ata_google.cloud.security.publicca.v1.json | 2 +- ...oogle.cloud.security.publicca.v1beta1.json | 2 +- ...st_public_certificate_authority_service.py | 56 +++ ...st_public_certificate_authority_service.py | 56 +++ packages/google-cloud-quotas/README.rst | 4 +- .../google/cloud/cloudquotas/gapic_version.py | 2 +- .../cloud/cloudquotas_v1/gapic_version.py | 2 +- .../services/cloud_quotas/client.py | 29 ++ .../services/cloud_quotas/transports/rest.py | 191 +++++++- .../cloud/cloudquotas_v1beta/gapic_version.py | 2 +- .../services/cloud_quotas/client.py | 29 ++ .../services/cloud_quotas/transports/rest.py | 191 +++++++- .../quota_adjuster_settings_manager/client.py | 29 ++ .../transports/rest.py | 71 ++- packages/google-cloud-quotas/noxfile.py | 81 +++- ...et_metadata_google.api.cloudquotas.v1.json | 2 +- ...etadata_google.api.cloudquotas.v1beta.json | 2 +- .../gapic/cloudquotas_v1/test_cloud_quotas.py | 86 ++++ .../cloudquotas_v1beta/test_cloud_quotas.py | 86 ++++ .../test_quota_adjuster_settings_manager.py | 68 +++ .../README.rst | 4 +- .../rapidmigrationassessment/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../rapid_migration_assessment/client.py | 117 +++-- .../transports/rest.py | 313 +++++++++++- .../noxfile.py | 81 +++- ...gle.cloud.rapidmigrationassessment.v1.json | 2 +- .../test_rapid_migration_assessment.py | 113 +++++ .../README.rst | 4 +- .../recaptchaenterprise/gapic_version.py | 2 +- .../recaptchaenterprise_v1/gapic_version.py | 2 +- .../recaptcha_enterprise_service/client.py | 29 ++ .../noxfile.py | 81 +++- ...a_google.cloud.recaptchaenterprise.v1.json | 2 +- .../test_recaptcha_enterprise_service.py | 51 ++ .../README.rst | 4 +- .../recommendationengine/gapic_version.py | 2 +- .../gapic_version.py | 2 +- .../services/catalog_service/client.py | 29 ++ .../catalog_service/transports/rest.py | 158 +++++- .../prediction_api_key_registry/client.py | 29 ++ .../transports/rest.py | 74 ++- .../services/prediction_service/client.py | 29 ++ .../prediction_service/transports/rest.py | 33 +- .../services/user_event_service/client.py | 29 ++ .../user_event_service/transports/rest.py | 158 +++++- .../noxfile.py | 81 +++- ...le.cloud.recommendationengine.v1beta1.json | 2 +- .../test_catalog_service.py | 82 ++++ .../test_prediction_api_key_registry.py | 68 +++ .../test_prediction_service.py | 55 +++ .../test_user_event_service.py | 83 ++++ packages/google-cloud-recommender/README.rst | 4 +- .../google/cloud/recommender/gapic_version.py | 2 +- .../cloud/recommender_v1/gapic_version.py | 2 +- .../services/recommender/client.py | 29 ++ .../services/recommender/transports/rest.py | 425 +++++++++++++++- .../recommender_v1beta1/gapic_version.py | 2 +- .../services/recommender/client.py | 29 ++ .../services/recommender/transports/rest.py | 459 ++++++++++++++++-- packages/google-cloud-recommender/noxfile.py | 81 +++- ..._metadata_google.cloud.recommender.v1.json | 2 +- ...data_google.cloud.recommender.v1beta1.json | 2 +- .../gapic/recommender_v1/test_recommender.py | 142 ++++++ .../recommender_v1beta1/test_recommender.py | 152 ++++++ .../google-cloud-redis-cluster/README.rst | 4 +- .../cloud/redis_cluster/gapic_version.py | 2 +- .../cloud/redis_cluster_v1/gapic_version.py | 2 +- .../services/cloud_redis_cluster/client.py | 117 +++-- .../cloud_redis_cluster/transports/rest.py | 453 +++++++++++++++-- .../redis_cluster_v1beta1/gapic_version.py | 2 +- .../services/cloud_redis_cluster/client.py | 117 +++-- .../cloud_redis_cluster/transports/rest.py | 453 +++++++++++++++-- .../google-cloud-redis-cluster/noxfile.py | 81 +++- ...etadata_google.cloud.redis.cluster.v1.json | 2 +- ...ta_google.cloud.redis.cluster.v1beta1.json | 2 +- .../test_cloud_redis_cluster.py | 139 ++++++ .../test_cloud_redis_cluster.py | 139 ++++++ packages/google-cloud-redis/README.rst | 4 +- .../google/cloud/redis/gapic_version.py | 2 +- .../google/cloud/redis_v1/gapic_version.py | 2 +- .../redis_v1/services/cloud_redis/client.py | 117 +++-- .../services/cloud_redis/transports/rest.py | 343 ++++++++++++- .../cloud/redis_v1beta1/gapic_version.py | 2 +- .../services/cloud_redis/client.py | 29 ++ .../services/cloud_redis/transports/rest.py | 343 ++++++++++++- packages/google-cloud-redis/noxfile.py | 81 +++- ...nippet_metadata_google.cloud.redis.v1.json | 2 +- ...t_metadata_google.cloud.redis.v1beta1.json | 2 +- .../unit/gapic/redis_v1/test_cloud_redis.py | 107 ++++ .../gapic/redis_v1beta1/test_cloud_redis.py | 107 ++++ .../google-cloud-resource-settings/README.rst | 4 +- .../cloud/resourcesettings/gapic_version.py | 2 +- .../resourcesettings_v1/gapic_version.py | 2 +- .../resource_settings_service/client.py | 29 ++ .../transports/rest.py | 95 +++- .../google-cloud-resource-settings/noxfile.py | 81 +++- ...data_google.cloud.resourcesettings.v1.json | 2 +- .../test_resource_settings_service.py | 71 +++ packages/google-cloud-retail/README.rst | 4 +- .../google/cloud/retail/gapic_version.py | 2 +- .../google/cloud/retail_v2/gapic_version.py | 2 +- .../services/analytics_service/client.py | 73 ++- .../analytics_service/transports/rest.py | 31 +- .../services/catalog_service/client.py | 73 ++- .../catalog_service/transports/rest.py | 315 +++++++++++- .../services/completion_service/client.py | 73 ++- .../completion_service/transports/rest.py | 65 ++- .../services/control_service/client.py | 73 ++- .../control_service/transports/rest.py | 126 ++++- .../generative_question_service/client.py | 73 ++- .../transports/rest.py | 185 ++++++- .../services/model_service/client.py | 73 ++- .../services/model_service/transports/rest.py | 213 +++++++- .../services/prediction_service/client.py | 73 ++- .../prediction_service/transports/rest.py | 33 +- .../services/product_service/client.py | 73 ++- .../product_service/transports/rest.py | 343 ++++++++++++- .../services/search_service/client.py | 73 ++- .../search_service/transports/rest.py | 31 +- .../services/serving_config_service/client.py | 73 ++- .../serving_config_service/transports/rest.py | 197 +++++++- .../services/user_event_service/client.py | 73 ++- .../user_event_service/transports/rest.py | 155 +++++- .../cloud/retail_v2alpha/gapic_version.py | 2 +- .../services/analytics_service/client.py | 73 ++- .../analytics_service/transports/rest.py | 31 +- .../services/branch_service/client.py | 73 ++- .../branch_service/transports/rest.py | 62 ++- .../services/catalog_service/client.py | 73 ++- .../catalog_service/transports/rest.py | 352 +++++++++++++- .../services/completion_service/client.py | 73 ++- .../completion_service/transports/rest.py | 65 ++- .../services/control_service/client.py | 73 ++- .../control_service/transports/rest.py | 126 ++++- .../generative_question_service/client.py | 73 ++- .../transports/rest.py | 185 ++++++- .../client.py | 73 ++- .../transports/rest.py | 71 ++- .../services/model_service/client.py | 73 ++- .../services/model_service/transports/rest.py | 213 +++++++- .../services/prediction_service/client.py | 73 ++- .../prediction_service/transports/rest.py | 33 +- .../services/product_service/client.py | 73 ++- .../product_service/transports/rest.py | 374 +++++++++++++- .../services/project_service/client.py | 73 ++- .../project_service/transports/rest.py | 251 +++++++++- .../services/search_service/client.py | 73 ++- .../search_service/transports/rest.py | 31 +- .../services/serving_config_service/client.py | 73 ++- .../serving_config_service/transports/rest.py | 197 +++++++- .../services/user_event_service/client.py | 73 ++- .../user_event_service/transports/rest.py | 186 ++++++- .../cloud/retail_v2beta/gapic_version.py | 2 +- .../services/analytics_service/client.py | 73 ++- .../analytics_service/transports/rest.py | 31 +- .../services/catalog_service/client.py | 73 ++- .../catalog_service/transports/rest.py | 352 +++++++++++++- .../services/completion_service/client.py | 73 ++- .../completion_service/transports/rest.py | 65 ++- .../services/control_service/client.py | 73 ++- .../control_service/transports/rest.py | 126 ++++- .../generative_question_service/client.py | 73 ++- .../transports/rest.py | 185 ++++++- .../services/model_service/client.py | 73 ++- .../services/model_service/transports/rest.py | 213 +++++++- .../services/prediction_service/client.py | 73 ++- .../prediction_service/transports/rest.py | 33 +- .../services/product_service/client.py | 73 ++- .../product_service/transports/rest.py | 374 +++++++++++++- .../services/project_service/client.py | 73 ++- .../project_service/transports/rest.py | 62 ++- .../services/search_service/client.py | 73 ++- .../search_service/transports/rest.py | 31 +- .../services/serving_config_service/client.py | 73 ++- .../serving_config_service/transports/rest.py | 197 +++++++- .../services/user_event_service/client.py | 73 ++- .../user_event_service/transports/rest.py | 186 ++++++- packages/google-cloud-retail/noxfile.py | 81 +++- ...ippet_metadata_google.cloud.retail.v2.json | 2 +- ..._metadata_google.cloud.retail.v2alpha.json | 2 +- ...t_metadata_google.cloud.retail.v2beta.json | 2 +- .../gapic/retail_v2/test_analytics_service.py | 56 +++ .../gapic/retail_v2/test_catalog_service.py | 114 +++++ .../retail_v2/test_completion_service.py | 64 +++ .../gapic/retail_v2/test_control_service.py | 73 +++ .../test_generative_question_service.py | 95 ++++ .../gapic/retail_v2/test_model_service.py | 85 ++++ .../retail_v2/test_prediction_service.py | 55 +++ .../gapic/retail_v2/test_product_service.py | 112 +++++ .../gapic/retail_v2/test_search_service.py | 55 +++ .../retail_v2/test_serving_config_service.py | 88 ++++ .../retail_v2/test_user_event_service.py | 80 +++ .../retail_v2alpha/test_analytics_service.py | 56 +++ .../retail_v2alpha/test_branch_service.py | 63 +++ .../retail_v2alpha/test_catalog_service.py | 123 +++++ .../retail_v2alpha/test_completion_service.py | 64 +++ .../retail_v2alpha/test_control_service.py | 73 +++ .../test_generative_question_service.py | 95 ++++ ...st_merchant_center_account_link_service.py | 65 +++ .../retail_v2alpha/test_model_service.py | 85 ++++ .../retail_v2alpha/test_prediction_service.py | 55 +++ .../retail_v2alpha/test_product_service.py | 117 +++++ .../retail_v2alpha/test_project_service.py | 97 ++++ .../retail_v2alpha/test_search_service.py | 55 +++ .../test_serving_config_service.py | 88 ++++ .../retail_v2alpha/test_user_event_service.py | 86 ++++ .../retail_v2beta/test_analytics_service.py | 56 +++ .../retail_v2beta/test_catalog_service.py | 123 +++++ .../retail_v2beta/test_completion_service.py | 64 +++ .../retail_v2beta/test_control_service.py | 73 +++ .../test_generative_question_service.py | 95 ++++ .../gapic/retail_v2beta/test_model_service.py | 85 ++++ .../retail_v2beta/test_prediction_service.py | 55 +++ .../retail_v2beta/test_product_service.py | 117 +++++ .../retail_v2beta/test_project_service.py | 61 +++ .../retail_v2beta/test_search_service.py | 55 +++ .../test_serving_config_service.py | 88 ++++ .../retail_v2beta/test_user_event_service.py | 86 ++++ packages/google-cloud-scheduler/README.rst | 4 +- .../google/cloud/scheduler/gapic_version.py | 2 +- .../cloud/scheduler_v1/gapic_version.py | 2 +- .../services/cloud_scheduler/client.py | 73 ++- .../cloud_scheduler/transports/rest.py | 207 +++++++- .../cloud/scheduler_v1beta1/gapic_version.py | 2 +- .../services/cloud_scheduler/client.py | 73 ++- .../cloud_scheduler/transports/rest.py | 207 +++++++- packages/google-cloud-scheduler/noxfile.py | 81 +++- ...et_metadata_google.cloud.scheduler.v1.json | 2 +- ...tadata_google.cloud.scheduler.v1beta1.json | 2 +- .../scheduler_v1/test_cloud_scheduler.py | 85 ++++ .../scheduler_v1beta1/test_cloud_scheduler.py | 85 ++++ 265 files changed, 19165 insertions(+), 1656 deletions(-) diff --git a/packages/google-cloud-phishing-protection/README.rst b/packages/google-cloud-phishing-protection/README.rst index 328c65a99026..9bd380ff3cbc 100644 --- a/packages/google-cloud-phishing-protection/README.rst +++ b/packages/google-cloud-phishing-protection/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Phishing Protection.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Phishing Protection.: https://cloud.google.com/phishing-protection/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py index 43155ded0db3..558c8aab67c5 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.13.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/client.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/client.py index 83a86c06083b..7bd4265a1718 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/client.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -470,6 +472,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/transports/rest.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/transports/rest.py index 9cfcab23d3e4..5ce62dd94293 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/transports/rest.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/services/phishing_protection_service_v1_beta1/transports/rest.py @@ -102,12 +102,38 @@ def post_report_phishing( ) -> phishingprotection.ReportPhishingResponse: """Post-rpc interceptor for report_phishing - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_report_phishing_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PhishingProtectionServiceV1Beta1 server but before - it is returned to user code. + it is returned to user code. This `post_report_phishing` interceptor runs + before the `post_report_phishing_with_metadata` interceptor. """ return response + def post_report_phishing_with_metadata( + self, + response: phishingprotection.ReportPhishingResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + phishingprotection.ReportPhishingResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for report_phishing + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PhishingProtectionServiceV1Beta1 server but before it is returned to user code. + + We recommend only using this `post_report_phishing_with_metadata` + interceptor in new development instead of the `post_report_phishing` interceptor. + When both interceptors are used, this `post_report_phishing_with_metadata` interceptor runs after the + `post_report_phishing` interceptor. The (possibly modified) response returned by + `post_report_phishing` will be passed to + `post_report_phishing_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PhishingProtectionServiceV1Beta1RestStub: @@ -325,6 +351,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_report_phishing(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_report_phishing_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-phishing-protection/noxfile.py b/packages/google-cloud-phishing-protection/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-phishing-protection/noxfile.py +++ b/packages/google-cloud-phishing-protection/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json b/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json index 3178a97f5b86..18460381eb04 100644 --- a/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json +++ b/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-phishing-protection", - "version": "1.13.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-phishing-protection/tests/unit/gapic/phishingprotection_v1beta1/test_phishing_protection_service_v1_beta1.py b/packages/google-cloud-phishing-protection/tests/unit/gapic/phishingprotection_v1beta1/test_phishing_protection_service_v1_beta1.py index c1a7c97aff17..202a9d2ac96b 100644 --- a/packages/google-cloud-phishing-protection/tests/unit/gapic/phishingprotection_v1beta1/test_phishing_protection_service_v1_beta1.py +++ b/packages/google-cloud-phishing-protection/tests/unit/gapic/phishingprotection_v1beta1/test_phishing_protection_service_v1_beta1.py @@ -59,6 +59,13 @@ ) from google.cloud.phishingprotection_v1beta1.types import phishingprotection +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -353,6 +360,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PhishingProtectionServiceV1Beta1Client(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PhishingProtectionServiceV1Beta1Client(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1936,11 +1986,15 @@ def test_report_phishing_rest_interceptors(null_interceptor): transports.PhishingProtectionServiceV1Beta1RestInterceptor, "post_report_phishing", ) as post, mock.patch.object( + transports.PhishingProtectionServiceV1Beta1RestInterceptor, + "post_report_phishing_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PhishingProtectionServiceV1Beta1RestInterceptor, "pre_report_phishing", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = phishingprotection.ReportPhishingRequest.pb( phishingprotection.ReportPhishingRequest() ) @@ -1966,6 +2020,10 @@ def test_report_phishing_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = phishingprotection.ReportPhishingResponse() + post_with_metadata.return_value = ( + phishingprotection.ReportPhishingResponse(), + metadata, + ) client.report_phishing( request, @@ -1977,6 +2035,7 @@ def test_report_phishing_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-private-catalog/README.rst b/packages/google-cloud-private-catalog/README.rst index b6e1627d35a5..0cc09d301594 100644 --- a/packages/google-cloud-private-catalog/README.rst +++ b/packages/google-cloud-private-catalog/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Private Catalog.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Private Catalog.: https://cloud.google.com/private-catalog/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py index 956522e5b1bb..558c8aab67c5 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.9.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py index 956522e5b1bb..558c8aab67c5 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.9.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/client.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/client.py index e73aecb00d01..8e07944b2db6 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/client.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -536,6 +538,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/transports/rest.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/transports/rest.py index 98facb8d06c7..9f381a6c0463 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/transports/rest.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/services/private_catalog/transports/rest.py @@ -117,12 +117,37 @@ def post_search_catalogs( ) -> private_catalog.SearchCatalogsResponse: """Post-rpc interceptor for search_catalogs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_catalogs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivateCatalog server but before - it is returned to user code. + it is returned to user code. This `post_search_catalogs` interceptor runs + before the `post_search_catalogs_with_metadata` interceptor. """ return response + def post_search_catalogs_with_metadata( + self, + response: private_catalog.SearchCatalogsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + private_catalog.SearchCatalogsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for search_catalogs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivateCatalog server but before it is returned to user code. + + We recommend only using this `post_search_catalogs_with_metadata` + interceptor in new development instead of the `post_search_catalogs` interceptor. + When both interceptors are used, this `post_search_catalogs_with_metadata` interceptor runs after the + `post_search_catalogs` interceptor. The (possibly modified) response returned by + `post_search_catalogs` will be passed to + `post_search_catalogs_with_metadata`. + """ + return response, metadata + def pre_search_products( self, request: private_catalog.SearchProductsRequest, @@ -142,12 +167,37 @@ def post_search_products( ) -> private_catalog.SearchProductsResponse: """Post-rpc interceptor for search_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivateCatalog server but before - it is returned to user code. + it is returned to user code. This `post_search_products` interceptor runs + before the `post_search_products_with_metadata` interceptor. """ return response + def post_search_products_with_metadata( + self, + response: private_catalog.SearchProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + private_catalog.SearchProductsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for search_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivateCatalog server but before it is returned to user code. + + We recommend only using this `post_search_products_with_metadata` + interceptor in new development instead of the `post_search_products` interceptor. + When both interceptors are used, this `post_search_products_with_metadata` interceptor runs after the + `post_search_products` interceptor. The (possibly modified) response returned by + `post_search_products` will be passed to + `post_search_products_with_metadata`. + """ + return response, metadata + def pre_search_versions( self, request: private_catalog.SearchVersionsRequest, @@ -167,12 +217,37 @@ def post_search_versions( ) -> private_catalog.SearchVersionsResponse: """Post-rpc interceptor for search_versions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_versions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivateCatalog server but before - it is returned to user code. + it is returned to user code. This `post_search_versions` interceptor runs + before the `post_search_versions_with_metadata` interceptor. """ return response + def post_search_versions_with_metadata( + self, + response: private_catalog.SearchVersionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + private_catalog.SearchVersionsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for search_versions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivateCatalog server but before it is returned to user code. + + We recommend only using this `post_search_versions_with_metadata` + interceptor in new development instead of the `post_search_versions` interceptor. + When both interceptors are used, this `post_search_versions_with_metadata` interceptor runs after the + `post_search_versions` interceptor. The (possibly modified) response returned by + `post_search_versions` will be passed to + `post_search_versions_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PrivateCatalogRestStub: @@ -401,6 +476,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_catalogs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_catalogs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -546,6 +625,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -691,6 +774,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_versions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_versions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-private-catalog/noxfile.py b/packages/google-cloud-private-catalog/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-private-catalog/noxfile.py +++ b/packages/google-cloud-private-catalog/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json b/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json index 876894bbc459..acf623a1683e 100644 --- a/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json +++ b/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-catalog", - "version": "0.9.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-private-catalog/tests/unit/gapic/privatecatalog_v1beta1/test_private_catalog.py b/packages/google-cloud-private-catalog/tests/unit/gapic/privatecatalog_v1beta1/test_private_catalog.py index 10d0faf6f767..6a173917de71 100644 --- a/packages/google-cloud-private-catalog/tests/unit/gapic/privatecatalog_v1beta1/test_private_catalog.py +++ b/packages/google-cloud-private-catalog/tests/unit/gapic/privatecatalog_v1beta1/test_private_catalog.py @@ -60,6 +60,13 @@ ) from google.cloud.privatecatalog_v1beta1.types import private_catalog +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -318,6 +325,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PrivateCatalogClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PrivateCatalogClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3348,10 +3398,13 @@ def test_search_catalogs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivateCatalogRestInterceptor, "post_search_catalogs" ) as post, mock.patch.object( + transports.PrivateCatalogRestInterceptor, "post_search_catalogs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PrivateCatalogRestInterceptor, "pre_search_catalogs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = private_catalog.SearchCatalogsRequest.pb( private_catalog.SearchCatalogsRequest() ) @@ -3377,6 +3430,10 @@ def test_search_catalogs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = private_catalog.SearchCatalogsResponse() + post_with_metadata.return_value = ( + private_catalog.SearchCatalogsResponse(), + metadata, + ) client.search_catalogs( request, @@ -3388,6 +3445,7 @@ def test_search_catalogs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_products_rest_bad_request( @@ -3472,10 +3530,13 @@ def test_search_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivateCatalogRestInterceptor, "post_search_products" ) as post, mock.patch.object( + transports.PrivateCatalogRestInterceptor, "post_search_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PrivateCatalogRestInterceptor, "pre_search_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = private_catalog.SearchProductsRequest.pb( private_catalog.SearchProductsRequest() ) @@ -3501,6 +3562,10 @@ def test_search_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = private_catalog.SearchProductsResponse() + post_with_metadata.return_value = ( + private_catalog.SearchProductsResponse(), + metadata, + ) client.search_products( request, @@ -3512,6 +3577,7 @@ def test_search_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_versions_rest_bad_request( @@ -3596,10 +3662,13 @@ def test_search_versions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivateCatalogRestInterceptor, "post_search_versions" ) as post, mock.patch.object( + transports.PrivateCatalogRestInterceptor, "post_search_versions_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PrivateCatalogRestInterceptor, "pre_search_versions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = private_catalog.SearchVersionsRequest.pb( private_catalog.SearchVersionsRequest() ) @@ -3625,6 +3694,10 @@ def test_search_versions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = private_catalog.SearchVersionsResponse() + post_with_metadata.return_value = ( + private_catalog.SearchVersionsResponse(), + metadata, + ) client.search_versions( request, @@ -3636,6 +3709,7 @@ def test_search_versions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-privilegedaccessmanager/README.rst b/packages/google-cloud-privilegedaccessmanager/README.rst index 1ae6deaf93ca..2131d41afe43 100644 --- a/packages/google-cloud-privilegedaccessmanager/README.rst +++ b/packages/google-cloud-privilegedaccessmanager/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Privileged Access Manager API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Privileged Access Manager API.: https://cloud.google.com/iam/docs/pam-overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py index e9c4bb5650f3..558c8aab67c5 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.5" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/client.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/client.py index ab170cc3e144..604d4257cf64 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/client.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -545,6 +547,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2377,16 +2406,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2432,16 +2465,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -2543,16 +2580,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2598,16 +2639,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/transports/rest.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/transports/rest.py index 2b62bc33daac..8150ba30e039 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/transports/rest.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/services/privileged_access_manager/transports/rest.py @@ -208,12 +208,35 @@ def post_approve_grant( ) -> privilegedaccessmanager.Grant: """Post-rpc interceptor for approve_grant - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_approve_grant_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_approve_grant` interceptor runs + before the `post_approve_grant_with_metadata` interceptor. """ return response + def post_approve_grant_with_metadata( + self, + response: privilegedaccessmanager.Grant, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[privilegedaccessmanager.Grant, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for approve_grant + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_approve_grant_with_metadata` + interceptor in new development instead of the `post_approve_grant` interceptor. + When both interceptors are used, this `post_approve_grant_with_metadata` interceptor runs after the + `post_approve_grant` interceptor. The (possibly modified) response returned by + `post_approve_grant` will be passed to + `post_approve_grant_with_metadata`. + """ + return response, metadata + def pre_check_onboarding_status( self, request: privilegedaccessmanager.CheckOnboardingStatusRequest, @@ -234,12 +257,38 @@ def post_check_onboarding_status( ) -> privilegedaccessmanager.CheckOnboardingStatusResponse: """Post-rpc interceptor for check_onboarding_status - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_check_onboarding_status_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_check_onboarding_status` interceptor runs + before the `post_check_onboarding_status_with_metadata` interceptor. """ return response + def post_check_onboarding_status_with_metadata( + self, + response: privilegedaccessmanager.CheckOnboardingStatusResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.CheckOnboardingStatusResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for check_onboarding_status + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_check_onboarding_status_with_metadata` + interceptor in new development instead of the `post_check_onboarding_status` interceptor. + When both interceptors are used, this `post_check_onboarding_status_with_metadata` interceptor runs after the + `post_check_onboarding_status` interceptor. The (possibly modified) response returned by + `post_check_onboarding_status` will be passed to + `post_check_onboarding_status_with_metadata`. + """ + return response, metadata + def pre_create_entitlement( self, request: privilegedaccessmanager.CreateEntitlementRequest, @@ -260,12 +309,35 @@ def post_create_entitlement( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_entitlement - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_entitlement_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_create_entitlement` interceptor runs + before the `post_create_entitlement_with_metadata` interceptor. """ return response + def post_create_entitlement_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_entitlement + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_create_entitlement_with_metadata` + interceptor in new development instead of the `post_create_entitlement` interceptor. + When both interceptors are used, this `post_create_entitlement_with_metadata` interceptor runs after the + `post_create_entitlement` interceptor. The (possibly modified) response returned by + `post_create_entitlement` will be passed to + `post_create_entitlement_with_metadata`. + """ + return response, metadata + def pre_create_grant( self, request: privilegedaccessmanager.CreateGrantRequest, @@ -286,12 +358,35 @@ def post_create_grant( ) -> privilegedaccessmanager.Grant: """Post-rpc interceptor for create_grant - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_grant_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_create_grant` interceptor runs + before the `post_create_grant_with_metadata` interceptor. """ return response + def post_create_grant_with_metadata( + self, + response: privilegedaccessmanager.Grant, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[privilegedaccessmanager.Grant, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_grant + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_create_grant_with_metadata` + interceptor in new development instead of the `post_create_grant` interceptor. + When both interceptors are used, this `post_create_grant_with_metadata` interceptor runs after the + `post_create_grant` interceptor. The (possibly modified) response returned by + `post_create_grant` will be passed to + `post_create_grant_with_metadata`. + """ + return response, metadata + def pre_delete_entitlement( self, request: privilegedaccessmanager.DeleteEntitlementRequest, @@ -312,12 +407,35 @@ def post_delete_entitlement( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_entitlement - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_entitlement_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_delete_entitlement` interceptor runs + before the `post_delete_entitlement_with_metadata` interceptor. """ return response + def post_delete_entitlement_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_entitlement + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_delete_entitlement_with_metadata` + interceptor in new development instead of the `post_delete_entitlement` interceptor. + When both interceptors are used, this `post_delete_entitlement_with_metadata` interceptor runs after the + `post_delete_entitlement` interceptor. The (possibly modified) response returned by + `post_delete_entitlement` will be passed to + `post_delete_entitlement_with_metadata`. + """ + return response, metadata + def pre_deny_grant( self, request: privilegedaccessmanager.DenyGrantRequest, @@ -338,12 +456,35 @@ def post_deny_grant( ) -> privilegedaccessmanager.Grant: """Post-rpc interceptor for deny_grant - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_deny_grant_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_deny_grant` interceptor runs + before the `post_deny_grant_with_metadata` interceptor. """ return response + def post_deny_grant_with_metadata( + self, + response: privilegedaccessmanager.Grant, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[privilegedaccessmanager.Grant, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for deny_grant + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_deny_grant_with_metadata` + interceptor in new development instead of the `post_deny_grant` interceptor. + When both interceptors are used, this `post_deny_grant_with_metadata` interceptor runs after the + `post_deny_grant` interceptor. The (possibly modified) response returned by + `post_deny_grant` will be passed to + `post_deny_grant_with_metadata`. + """ + return response, metadata + def pre_get_entitlement( self, request: privilegedaccessmanager.GetEntitlementRequest, @@ -364,12 +505,37 @@ def post_get_entitlement( ) -> privilegedaccessmanager.Entitlement: """Post-rpc interceptor for get_entitlement - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_entitlement_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_get_entitlement` interceptor runs + before the `post_get_entitlement_with_metadata` interceptor. """ return response + def post_get_entitlement_with_metadata( + self, + response: privilegedaccessmanager.Entitlement, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.Entitlement, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_entitlement + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_get_entitlement_with_metadata` + interceptor in new development instead of the `post_get_entitlement` interceptor. + When both interceptors are used, this `post_get_entitlement_with_metadata` interceptor runs after the + `post_get_entitlement` interceptor. The (possibly modified) response returned by + `post_get_entitlement` will be passed to + `post_get_entitlement_with_metadata`. + """ + return response, metadata + def pre_get_grant( self, request: privilegedaccessmanager.GetGrantRequest, @@ -389,12 +555,35 @@ def post_get_grant( ) -> privilegedaccessmanager.Grant: """Post-rpc interceptor for get_grant - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_grant_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_get_grant` interceptor runs + before the `post_get_grant_with_metadata` interceptor. """ return response + def post_get_grant_with_metadata( + self, + response: privilegedaccessmanager.Grant, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[privilegedaccessmanager.Grant, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_grant + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_get_grant_with_metadata` + interceptor in new development instead of the `post_get_grant` interceptor. + When both interceptors are used, this `post_get_grant_with_metadata` interceptor runs after the + `post_get_grant` interceptor. The (possibly modified) response returned by + `post_get_grant` will be passed to + `post_get_grant_with_metadata`. + """ + return response, metadata + def pre_list_entitlements( self, request: privilegedaccessmanager.ListEntitlementsRequest, @@ -415,12 +604,38 @@ def post_list_entitlements( ) -> privilegedaccessmanager.ListEntitlementsResponse: """Post-rpc interceptor for list_entitlements - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_entitlements_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_list_entitlements` interceptor runs + before the `post_list_entitlements_with_metadata` interceptor. """ return response + def post_list_entitlements_with_metadata( + self, + response: privilegedaccessmanager.ListEntitlementsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.ListEntitlementsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_entitlements + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_list_entitlements_with_metadata` + interceptor in new development instead of the `post_list_entitlements` interceptor. + When both interceptors are used, this `post_list_entitlements_with_metadata` interceptor runs after the + `post_list_entitlements` interceptor. The (possibly modified) response returned by + `post_list_entitlements` will be passed to + `post_list_entitlements_with_metadata`. + """ + return response, metadata + def pre_list_grants( self, request: privilegedaccessmanager.ListGrantsRequest, @@ -441,12 +656,38 @@ def post_list_grants( ) -> privilegedaccessmanager.ListGrantsResponse: """Post-rpc interceptor for list_grants - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_grants_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_list_grants` interceptor runs + before the `post_list_grants_with_metadata` interceptor. """ return response + def post_list_grants_with_metadata( + self, + response: privilegedaccessmanager.ListGrantsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.ListGrantsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_grants + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_list_grants_with_metadata` + interceptor in new development instead of the `post_list_grants` interceptor. + When both interceptors are used, this `post_list_grants_with_metadata` interceptor runs after the + `post_list_grants` interceptor. The (possibly modified) response returned by + `post_list_grants` will be passed to + `post_list_grants_with_metadata`. + """ + return response, metadata + def pre_revoke_grant( self, request: privilegedaccessmanager.RevokeGrantRequest, @@ -467,12 +708,35 @@ def post_revoke_grant( ) -> operations_pb2.Operation: """Post-rpc interceptor for revoke_grant - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_revoke_grant_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_revoke_grant` interceptor runs + before the `post_revoke_grant_with_metadata` interceptor. """ return response + def post_revoke_grant_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for revoke_grant + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_revoke_grant_with_metadata` + interceptor in new development instead of the `post_revoke_grant` interceptor. + When both interceptors are used, this `post_revoke_grant_with_metadata` interceptor runs after the + `post_revoke_grant` interceptor. The (possibly modified) response returned by + `post_revoke_grant` will be passed to + `post_revoke_grant_with_metadata`. + """ + return response, metadata + def pre_search_entitlements( self, request: privilegedaccessmanager.SearchEntitlementsRequest, @@ -493,12 +757,38 @@ def post_search_entitlements( ) -> privilegedaccessmanager.SearchEntitlementsResponse: """Post-rpc interceptor for search_entitlements - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_entitlements_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_search_entitlements` interceptor runs + before the `post_search_entitlements_with_metadata` interceptor. """ return response + def post_search_entitlements_with_metadata( + self, + response: privilegedaccessmanager.SearchEntitlementsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.SearchEntitlementsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for search_entitlements + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_search_entitlements_with_metadata` + interceptor in new development instead of the `post_search_entitlements` interceptor. + When both interceptors are used, this `post_search_entitlements_with_metadata` interceptor runs after the + `post_search_entitlements` interceptor. The (possibly modified) response returned by + `post_search_entitlements` will be passed to + `post_search_entitlements_with_metadata`. + """ + return response, metadata + def pre_search_grants( self, request: privilegedaccessmanager.SearchGrantsRequest, @@ -519,12 +809,38 @@ def post_search_grants( ) -> privilegedaccessmanager.SearchGrantsResponse: """Post-rpc interceptor for search_grants - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_grants_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_search_grants` interceptor runs + before the `post_search_grants_with_metadata` interceptor. """ return response + def post_search_grants_with_metadata( + self, + response: privilegedaccessmanager.SearchGrantsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + privilegedaccessmanager.SearchGrantsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for search_grants + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_search_grants_with_metadata` + interceptor in new development instead of the `post_search_grants` interceptor. + When both interceptors are used, this `post_search_grants_with_metadata` interceptor runs after the + `post_search_grants` interceptor. The (possibly modified) response returned by + `post_search_grants` will be passed to + `post_search_grants_with_metadata`. + """ + return response, metadata + def pre_update_entitlement( self, request: privilegedaccessmanager.UpdateEntitlementRequest, @@ -545,12 +861,35 @@ def post_update_entitlement( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_entitlement - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_entitlement_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PrivilegedAccessManager server but before - it is returned to user code. + it is returned to user code. This `post_update_entitlement` interceptor runs + before the `post_update_entitlement_with_metadata` interceptor. """ return response + def post_update_entitlement_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_entitlement + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PrivilegedAccessManager server but before it is returned to user code. + + We recommend only using this `post_update_entitlement_with_metadata` + interceptor in new development instead of the `post_update_entitlement` interceptor. + When both interceptors are used, this `post_update_entitlement_with_metadata` interceptor runs after the + `post_update_entitlement` interceptor. The (possibly modified) response returned by + `post_update_entitlement` will be passed to + `post_update_entitlement_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -981,6 +1320,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_approve_grant(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_approve_grant_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1124,6 +1467,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_check_onboarding_status(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_check_onboarding_status_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1280,6 +1627,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_entitlement(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_entitlement_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1430,6 +1781,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_grant(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_grant_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1576,6 +1931,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_entitlement(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_entitlement_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1726,6 +2085,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_deny_grant(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_deny_grant_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1874,6 +2237,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_entitlement(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_entitlement_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2020,6 +2387,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_grant(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_grant_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2168,6 +2539,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_entitlements(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_entitlements_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2316,6 +2691,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_grants(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_grants_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2466,6 +2845,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_revoke_grant(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_revoke_grant_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2611,6 +2994,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_entitlements(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_entitlements_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2756,6 +3143,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search_grants(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_grants_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2910,6 +3301,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_entitlement(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_entitlement_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-privilegedaccessmanager/noxfile.py b/packages/google-cloud-privilegedaccessmanager/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-privilegedaccessmanager/noxfile.py +++ b/packages/google-cloud-privilegedaccessmanager/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json b/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json index f33872e2f3b1..ec4443c5cbc9 100644 --- a/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json +++ b/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-privilegedaccessmanager", - "version": "0.1.5" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-privilegedaccessmanager/tests/unit/gapic/privilegedaccessmanager_v1/test_privileged_access_manager.py b/packages/google-cloud-privilegedaccessmanager/tests/unit/gapic/privilegedaccessmanager_v1/test_privileged_access_manager.py index b1aad649ba00..0b911789b90b 100644 --- a/packages/google-cloud-privilegedaccessmanager/tests/unit/gapic/privilegedaccessmanager_v1/test_privileged_access_manager.py +++ b/packages/google-cloud-privilegedaccessmanager/tests/unit/gapic/privilegedaccessmanager_v1/test_privileged_access_manager.py @@ -76,6 +76,13 @@ ) from google.cloud.privilegedaccessmanager_v1.types import privilegedaccessmanager +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -351,6 +358,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PrivilegedAccessManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PrivilegedAccessManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -9768,10 +9818,14 @@ def test_check_onboarding_status_rest_interceptors(null_interceptor): transports.PrivilegedAccessManagerRestInterceptor, "post_check_onboarding_status", ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_check_onboarding_status_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_check_onboarding_status" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.CheckOnboardingStatusRequest.pb( privilegedaccessmanager.CheckOnboardingStatusRequest() ) @@ -9797,6 +9851,10 @@ def test_check_onboarding_status_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.CheckOnboardingStatusResponse() + post_with_metadata.return_value = ( + privilegedaccessmanager.CheckOnboardingStatusResponse(), + metadata, + ) client.check_onboarding_status( request, @@ -9808,6 +9866,7 @@ def test_check_onboarding_status_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_entitlements_rest_bad_request( @@ -9894,10 +9953,14 @@ def test_list_entitlements_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_list_entitlements" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_list_entitlements_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_list_entitlements" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.ListEntitlementsRequest.pb( privilegedaccessmanager.ListEntitlementsRequest() ) @@ -9923,6 +9986,10 @@ def test_list_entitlements_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.ListEntitlementsResponse() + post_with_metadata.return_value = ( + privilegedaccessmanager.ListEntitlementsResponse(), + metadata, + ) client.list_entitlements( request, @@ -9934,6 +10001,7 @@ def test_list_entitlements_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_entitlements_rest_bad_request( @@ -10020,10 +10088,14 @@ def test_search_entitlements_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_search_entitlements" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_search_entitlements_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_search_entitlements" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.SearchEntitlementsRequest.pb( privilegedaccessmanager.SearchEntitlementsRequest() ) @@ -10049,6 +10121,10 @@ def test_search_entitlements_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.SearchEntitlementsResponse() + post_with_metadata.return_value = ( + privilegedaccessmanager.SearchEntitlementsResponse(), + metadata, + ) client.search_entitlements( request, @@ -10060,6 +10136,7 @@ def test_search_entitlements_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_entitlement_rest_bad_request( @@ -10148,10 +10225,14 @@ def test_get_entitlement_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_get_entitlement" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_get_entitlement_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_get_entitlement" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.GetEntitlementRequest.pb( privilegedaccessmanager.GetEntitlementRequest() ) @@ -10177,6 +10258,10 @@ def test_get_entitlement_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.Entitlement() + post_with_metadata.return_value = ( + privilegedaccessmanager.Entitlement(), + metadata, + ) client.get_entitlement( request, @@ -10188,6 +10273,7 @@ def test_get_entitlement_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_entitlement_rest_bad_request( @@ -10384,10 +10470,14 @@ def test_create_entitlement_rest_interceptors(null_interceptor): ), mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_create_entitlement" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_create_entitlement_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_create_entitlement" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.CreateEntitlementRequest.pb( privilegedaccessmanager.CreateEntitlementRequest() ) @@ -10411,6 +10501,7 @@ def test_create_entitlement_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_entitlement( request, @@ -10422,6 +10513,7 @@ def test_create_entitlement_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_entitlement_rest_bad_request( @@ -10502,10 +10594,14 @@ def test_delete_entitlement_rest_interceptors(null_interceptor): ), mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_delete_entitlement" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_delete_entitlement_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_delete_entitlement" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.DeleteEntitlementRequest.pb( privilegedaccessmanager.DeleteEntitlementRequest() ) @@ -10529,6 +10625,7 @@ def test_delete_entitlement_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_entitlement( request, @@ -10540,6 +10637,7 @@ def test_delete_entitlement_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_entitlement_rest_bad_request( @@ -10744,10 +10842,14 @@ def test_update_entitlement_rest_interceptors(null_interceptor): ), mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_update_entitlement" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_update_entitlement_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_update_entitlement" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.UpdateEntitlementRequest.pb( privilegedaccessmanager.UpdateEntitlementRequest() ) @@ -10771,6 +10873,7 @@ def test_update_entitlement_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_entitlement( request, @@ -10782,6 +10885,7 @@ def test_update_entitlement_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_grants_rest_bad_request( @@ -10868,10 +10972,14 @@ def test_list_grants_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_list_grants" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_list_grants_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_list_grants" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.ListGrantsRequest.pb( privilegedaccessmanager.ListGrantsRequest() ) @@ -10897,6 +11005,10 @@ def test_list_grants_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.ListGrantsResponse() + post_with_metadata.return_value = ( + privilegedaccessmanager.ListGrantsResponse(), + metadata, + ) client.list_grants( request, @@ -10908,6 +11020,7 @@ def test_list_grants_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_search_grants_rest_bad_request( @@ -10992,10 +11105,14 @@ def test_search_grants_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_search_grants" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_search_grants_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_search_grants" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.SearchGrantsRequest.pb( privilegedaccessmanager.SearchGrantsRequest() ) @@ -11021,6 +11138,10 @@ def test_search_grants_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.SearchGrantsResponse() + post_with_metadata.return_value = ( + privilegedaccessmanager.SearchGrantsResponse(), + metadata, + ) client.search_grants( request, @@ -11032,6 +11153,7 @@ def test_search_grants_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_grant_rest_bad_request( @@ -11128,10 +11250,14 @@ def test_get_grant_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_get_grant" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_get_grant_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_get_grant" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.GetGrantRequest.pb( privilegedaccessmanager.GetGrantRequest() ) @@ -11157,6 +11283,7 @@ def test_get_grant_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.Grant() + post_with_metadata.return_value = privilegedaccessmanager.Grant(), metadata client.get_grant( request, @@ -11168,6 +11295,7 @@ def test_get_grant_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_grant_rest_bad_request( @@ -11384,10 +11512,14 @@ def test_create_grant_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_create_grant" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_create_grant_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_create_grant" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.CreateGrantRequest.pb( privilegedaccessmanager.CreateGrantRequest() ) @@ -11413,6 +11545,7 @@ def test_create_grant_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.Grant() + post_with_metadata.return_value = privilegedaccessmanager.Grant(), metadata client.create_grant( request, @@ -11424,6 +11557,7 @@ def test_create_grant_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_approve_grant_rest_bad_request( @@ -11520,10 +11654,14 @@ def test_approve_grant_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_approve_grant" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_approve_grant_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_approve_grant" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.ApproveGrantRequest.pb( privilegedaccessmanager.ApproveGrantRequest() ) @@ -11549,6 +11687,7 @@ def test_approve_grant_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.Grant() + post_with_metadata.return_value = privilegedaccessmanager.Grant(), metadata client.approve_grant( request, @@ -11560,6 +11699,7 @@ def test_approve_grant_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_deny_grant_rest_bad_request( @@ -11656,10 +11796,14 @@ def test_deny_grant_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_deny_grant" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_deny_grant_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_deny_grant" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.DenyGrantRequest.pb( privilegedaccessmanager.DenyGrantRequest() ) @@ -11685,6 +11829,7 @@ def test_deny_grant_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = privilegedaccessmanager.Grant() + post_with_metadata.return_value = privilegedaccessmanager.Grant(), metadata client.deny_grant( request, @@ -11696,6 +11841,7 @@ def test_deny_grant_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_revoke_grant_rest_bad_request( @@ -11780,10 +11926,14 @@ def test_revoke_grant_rest_interceptors(null_interceptor): ), mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "post_revoke_grant" ) as post, mock.patch.object( + transports.PrivilegedAccessManagerRestInterceptor, + "post_revoke_grant_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PrivilegedAccessManagerRestInterceptor, "pre_revoke_grant" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = privilegedaccessmanager.RevokeGrantRequest.pb( privilegedaccessmanager.RevokeGrantRequest() ) @@ -11807,6 +11957,7 @@ def test_revoke_grant_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.revoke_grant( request, @@ -11818,6 +11969,7 @@ def test_revoke_grant_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-public-ca/README.rst b/packages/google-cloud-public-ca/README.rst index c4649b75a970..3ac34a2569c5 100644 --- a/packages/google-cloud-public-ca/README.rst +++ b/packages/google-cloud-public-ca/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Public Certificate Authority.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Public Certificate Authority.: https://cloud.google.com/certificate-manager/docs/public-ca -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py index 7d28791e7569..558c8aab67c5 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.3.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py index 7d28791e7569..558c8aab67c5 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.3.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/client.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/client.py index 704e6d8b1ac4..071287296879 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/client.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -497,6 +499,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/transports/rest.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/transports/rest.py index 9630069457c7..4f2ecf339bec 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/transports/rest.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/services/public_certificate_authority_service/transports/rest.py @@ -101,12 +101,35 @@ def post_create_external_account_key( ) -> resources.ExternalAccountKey: """Post-rpc interceptor for create_external_account_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_external_account_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PublicCertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_external_account_key` interceptor runs + before the `post_create_external_account_key_with_metadata` interceptor. """ return response + def post_create_external_account_key_with_metadata( + self, + response: resources.ExternalAccountKey, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.ExternalAccountKey, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_external_account_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PublicCertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_external_account_key_with_metadata` + interceptor in new development instead of the `post_create_external_account_key` interceptor. + When both interceptors are used, this `post_create_external_account_key_with_metadata` interceptor runs after the + `post_create_external_account_key` interceptor. The (possibly modified) response returned by + `post_create_external_account_key` will be passed to + `post_create_external_account_key_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PublicCertificateAuthorityServiceRestStub: @@ -335,6 +358,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_external_account_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_external_account_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py index 7d28791e7569..558c8aab67c5 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.3.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/client.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/client.py index 09bf779aa68b..60f7163878ef 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/client.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -497,6 +499,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/transports/rest.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/transports/rest.py index 74951c6c5f53..fc591b6e93ec 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/transports/rest.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/services/public_certificate_authority_service/transports/rest.py @@ -101,12 +101,35 @@ def post_create_external_account_key( ) -> resources.ExternalAccountKey: """Post-rpc interceptor for create_external_account_key - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_external_account_key_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PublicCertificateAuthorityService server but before - it is returned to user code. + it is returned to user code. This `post_create_external_account_key` interceptor runs + before the `post_create_external_account_key_with_metadata` interceptor. """ return response + def post_create_external_account_key_with_metadata( + self, + response: resources.ExternalAccountKey, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.ExternalAccountKey, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_external_account_key + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PublicCertificateAuthorityService server but before it is returned to user code. + + We recommend only using this `post_create_external_account_key_with_metadata` + interceptor in new development instead of the `post_create_external_account_key` interceptor. + When both interceptors are used, this `post_create_external_account_key_with_metadata` interceptor runs after the + `post_create_external_account_key` interceptor. The (possibly modified) response returned by + `post_create_external_account_key` will be passed to + `post_create_external_account_key_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PublicCertificateAuthorityServiceRestStub: @@ -335,6 +358,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_external_account_key(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_external_account_key_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-public-ca/noxfile.py b/packages/google-cloud-public-ca/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-public-ca/noxfile.py +++ b/packages/google-cloud-public-ca/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json index 5546e0ffdcda..0e5cae8caf1b 100644 --- a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json +++ b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-security-publicca", - "version": "0.3.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json index 58813ff38440..5871e5024384 100644 --- a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json +++ b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-public-ca", - "version": "0.3.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1/test_public_certificate_authority_service.py b/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1/test_public_certificate_authority_service.py index 51755be9ebeb..3aba9837c4c4 100644 --- a/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1/test_public_certificate_authority_service.py +++ b/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1/test_public_certificate_authority_service.py @@ -59,6 +59,13 @@ ) from google.cloud.security.publicca_v1.types import resources, service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -349,6 +356,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PublicCertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PublicCertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2056,11 +2106,15 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): transports.PublicCertificateAuthorityServiceRestInterceptor, "post_create_external_account_key", ) as post, mock.patch.object( + transports.PublicCertificateAuthorityServiceRestInterceptor, + "post_create_external_account_key_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PublicCertificateAuthorityServiceRestInterceptor, "pre_create_external_account_key", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateExternalAccountKeyRequest.pb( service.CreateExternalAccountKeyRequest() ) @@ -2086,6 +2140,7 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.ExternalAccountKey() + post_with_metadata.return_value = resources.ExternalAccountKey(), metadata client.create_external_account_key( request, @@ -2097,6 +2152,7 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1beta1/test_public_certificate_authority_service.py b/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1beta1/test_public_certificate_authority_service.py index a48bf32dac87..fb4af1a632f6 100644 --- a/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1beta1/test_public_certificate_authority_service.py +++ b/packages/google-cloud-public-ca/tests/unit/gapic/publicca_v1beta1/test_public_certificate_authority_service.py @@ -59,6 +59,13 @@ ) from google.cloud.security.publicca_v1beta1.types import resources, service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -349,6 +356,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PublicCertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PublicCertificateAuthorityServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2056,11 +2106,15 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): transports.PublicCertificateAuthorityServiceRestInterceptor, "post_create_external_account_key", ) as post, mock.patch.object( + transports.PublicCertificateAuthorityServiceRestInterceptor, + "post_create_external_account_key_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PublicCertificateAuthorityServiceRestInterceptor, "pre_create_external_account_key", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = service.CreateExternalAccountKeyRequest.pb( service.CreateExternalAccountKeyRequest() ) @@ -2086,6 +2140,7 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.ExternalAccountKey() + post_with_metadata.return_value = resources.ExternalAccountKey(), metadata client.create_external_account_key( request, @@ -2097,6 +2152,7 @@ def test_create_external_account_key_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-quotas/README.rst b/packages/google-cloud-quotas/README.rst index 70150d437c65..8fec838f9045 100644 --- a/packages/google-cloud-quotas/README.rst +++ b/packages/google-cloud-quotas/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Quotas API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Quotas API.: https://cloud.google.com/docs/quota/api-overview -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py index 564cdfade642..558c8aab67c5 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py index 564cdfade642..558c8aab67c5 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/client.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/client.py index 90b364da2069..c829bd7673ce 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/client.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -519,6 +521,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/transports/rest.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/transports/rest.py index 353af1a39cf1..5c2246273a4b 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/transports/rest.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/services/cloud_quotas/transports/rest.py @@ -142,12 +142,35 @@ def post_create_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for create_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_create_quota_preference` interceptor runs + before the `post_create_quota_preference_with_metadata` interceptor. """ return response + def post_create_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_create_quota_preference_with_metadata` + interceptor in new development instead of the `post_create_quota_preference` interceptor. + When both interceptors are used, this `post_create_quota_preference_with_metadata` interceptor runs after the + `post_create_quota_preference` interceptor. The (possibly modified) response returned by + `post_create_quota_preference` will be passed to + `post_create_quota_preference_with_metadata`. + """ + return response, metadata + def pre_get_quota_info( self, request: cloudquotas.GetQuotaInfoRequest, @@ -165,12 +188,35 @@ def pre_get_quota_info( def post_get_quota_info(self, response: resources.QuotaInfo) -> resources.QuotaInfo: """Post-rpc interceptor for get_quota_info - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_quota_info_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_get_quota_info` interceptor runs + before the `post_get_quota_info_with_metadata` interceptor. """ return response + def post_get_quota_info_with_metadata( + self, + response: resources.QuotaInfo, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaInfo, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_quota_info + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_get_quota_info_with_metadata` + interceptor in new development instead of the `post_get_quota_info` interceptor. + When both interceptors are used, this `post_get_quota_info_with_metadata` interceptor runs after the + `post_get_quota_info` interceptor. The (possibly modified) response returned by + `post_get_quota_info` will be passed to + `post_get_quota_info_with_metadata`. + """ + return response, metadata + def pre_get_quota_preference( self, request: cloudquotas.GetQuotaPreferenceRequest, @@ -190,12 +236,35 @@ def post_get_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for get_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_get_quota_preference` interceptor runs + before the `post_get_quota_preference_with_metadata` interceptor. """ return response + def post_get_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_get_quota_preference_with_metadata` + interceptor in new development instead of the `post_get_quota_preference` interceptor. + When both interceptors are used, this `post_get_quota_preference_with_metadata` interceptor runs after the + `post_get_quota_preference` interceptor. The (possibly modified) response returned by + `post_get_quota_preference` will be passed to + `post_get_quota_preference_with_metadata`. + """ + return response, metadata + def pre_list_quota_infos( self, request: cloudquotas.ListQuotaInfosRequest, @@ -215,12 +284,37 @@ def post_list_quota_infos( ) -> cloudquotas.ListQuotaInfosResponse: """Post-rpc interceptor for list_quota_infos - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_quota_infos_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_list_quota_infos` interceptor runs + before the `post_list_quota_infos_with_metadata` interceptor. """ return response + def post_list_quota_infos_with_metadata( + self, + response: cloudquotas.ListQuotaInfosResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudquotas.ListQuotaInfosResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_quota_infos + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_list_quota_infos_with_metadata` + interceptor in new development instead of the `post_list_quota_infos` interceptor. + When both interceptors are used, this `post_list_quota_infos_with_metadata` interceptor runs after the + `post_list_quota_infos` interceptor. The (possibly modified) response returned by + `post_list_quota_infos` will be passed to + `post_list_quota_infos_with_metadata`. + """ + return response, metadata + def pre_list_quota_preferences( self, request: cloudquotas.ListQuotaPreferencesRequest, @@ -240,12 +334,38 @@ def post_list_quota_preferences( ) -> cloudquotas.ListQuotaPreferencesResponse: """Post-rpc interceptor for list_quota_preferences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_quota_preferences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_list_quota_preferences` interceptor runs + before the `post_list_quota_preferences_with_metadata` interceptor. """ return response + def post_list_quota_preferences_with_metadata( + self, + response: cloudquotas.ListQuotaPreferencesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudquotas.ListQuotaPreferencesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_quota_preferences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_list_quota_preferences_with_metadata` + interceptor in new development instead of the `post_list_quota_preferences` interceptor. + When both interceptors are used, this `post_list_quota_preferences_with_metadata` interceptor runs after the + `post_list_quota_preferences` interceptor. The (possibly modified) response returned by + `post_list_quota_preferences` will be passed to + `post_list_quota_preferences_with_metadata`. + """ + return response, metadata + def pre_update_quota_preference( self, request: cloudquotas.UpdateQuotaPreferenceRequest, @@ -266,12 +386,35 @@ def post_update_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for update_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_update_quota_preference` interceptor runs + before the `post_update_quota_preference_with_metadata` interceptor. """ return response + def post_update_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_update_quota_preference_with_metadata` + interceptor in new development instead of the `post_update_quota_preference` interceptor. + When both interceptors are used, this `post_update_quota_preference_with_metadata` interceptor runs after the + `post_update_quota_preference` interceptor. The (possibly modified) response returned by + `post_update_quota_preference` will be passed to + `post_update_quota_preference_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CloudQuotasRestStub: @@ -500,6 +643,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -647,6 +794,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_quota_info(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_quota_info_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -795,6 +946,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -940,6 +1095,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_quota_infos(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_quota_infos_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1087,6 +1246,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_quota_preferences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_quota_preferences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1244,6 +1407,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py index 564cdfade642..558c8aab67c5 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/client.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/client.py index 59d8de236aa8..d5c938001d57 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/client.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -519,6 +521,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/transports/rest.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/transports/rest.py index 886b606fc1b7..bf8b698eae72 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/transports/rest.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/cloud_quotas/transports/rest.py @@ -142,12 +142,35 @@ def post_create_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for create_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_create_quota_preference` interceptor runs + before the `post_create_quota_preference_with_metadata` interceptor. """ return response + def post_create_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_create_quota_preference_with_metadata` + interceptor in new development instead of the `post_create_quota_preference` interceptor. + When both interceptors are used, this `post_create_quota_preference_with_metadata` interceptor runs after the + `post_create_quota_preference` interceptor. The (possibly modified) response returned by + `post_create_quota_preference` will be passed to + `post_create_quota_preference_with_metadata`. + """ + return response, metadata + def pre_get_quota_info( self, request: cloudquotas.GetQuotaInfoRequest, @@ -165,12 +188,35 @@ def pre_get_quota_info( def post_get_quota_info(self, response: resources.QuotaInfo) -> resources.QuotaInfo: """Post-rpc interceptor for get_quota_info - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_quota_info_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_get_quota_info` interceptor runs + before the `post_get_quota_info_with_metadata` interceptor. """ return response + def post_get_quota_info_with_metadata( + self, + response: resources.QuotaInfo, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaInfo, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_quota_info + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_get_quota_info_with_metadata` + interceptor in new development instead of the `post_get_quota_info` interceptor. + When both interceptors are used, this `post_get_quota_info_with_metadata` interceptor runs after the + `post_get_quota_info` interceptor. The (possibly modified) response returned by + `post_get_quota_info` will be passed to + `post_get_quota_info_with_metadata`. + """ + return response, metadata + def pre_get_quota_preference( self, request: cloudquotas.GetQuotaPreferenceRequest, @@ -190,12 +236,35 @@ def post_get_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for get_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_get_quota_preference` interceptor runs + before the `post_get_quota_preference_with_metadata` interceptor. """ return response + def post_get_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_get_quota_preference_with_metadata` + interceptor in new development instead of the `post_get_quota_preference` interceptor. + When both interceptors are used, this `post_get_quota_preference_with_metadata` interceptor runs after the + `post_get_quota_preference` interceptor. The (possibly modified) response returned by + `post_get_quota_preference` will be passed to + `post_get_quota_preference_with_metadata`. + """ + return response, metadata + def pre_list_quota_infos( self, request: cloudquotas.ListQuotaInfosRequest, @@ -215,12 +284,37 @@ def post_list_quota_infos( ) -> cloudquotas.ListQuotaInfosResponse: """Post-rpc interceptor for list_quota_infos - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_quota_infos_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_list_quota_infos` interceptor runs + before the `post_list_quota_infos_with_metadata` interceptor. """ return response + def post_list_quota_infos_with_metadata( + self, + response: cloudquotas.ListQuotaInfosResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudquotas.ListQuotaInfosResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_quota_infos + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_list_quota_infos_with_metadata` + interceptor in new development instead of the `post_list_quota_infos` interceptor. + When both interceptors are used, this `post_list_quota_infos_with_metadata` interceptor runs after the + `post_list_quota_infos` interceptor. The (possibly modified) response returned by + `post_list_quota_infos` will be passed to + `post_list_quota_infos_with_metadata`. + """ + return response, metadata + def pre_list_quota_preferences( self, request: cloudquotas.ListQuotaPreferencesRequest, @@ -240,12 +334,38 @@ def post_list_quota_preferences( ) -> cloudquotas.ListQuotaPreferencesResponse: """Post-rpc interceptor for list_quota_preferences - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_quota_preferences_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_list_quota_preferences` interceptor runs + before the `post_list_quota_preferences_with_metadata` interceptor. """ return response + def post_list_quota_preferences_with_metadata( + self, + response: cloudquotas.ListQuotaPreferencesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudquotas.ListQuotaPreferencesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_quota_preferences + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_list_quota_preferences_with_metadata` + interceptor in new development instead of the `post_list_quota_preferences` interceptor. + When both interceptors are used, this `post_list_quota_preferences_with_metadata` interceptor runs after the + `post_list_quota_preferences` interceptor. The (possibly modified) response returned by + `post_list_quota_preferences` will be passed to + `post_list_quota_preferences_with_metadata`. + """ + return response, metadata + def pre_update_quota_preference( self, request: cloudquotas.UpdateQuotaPreferenceRequest, @@ -266,12 +386,35 @@ def post_update_quota_preference( ) -> resources.QuotaPreference: """Post-rpc interceptor for update_quota_preference - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_quota_preference_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudQuotas server but before - it is returned to user code. + it is returned to user code. This `post_update_quota_preference` interceptor runs + before the `post_update_quota_preference_with_metadata` interceptor. """ return response + def post_update_quota_preference_with_metadata( + self, + response: resources.QuotaPreference, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resources.QuotaPreference, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_quota_preference + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudQuotas server but before it is returned to user code. + + We recommend only using this `post_update_quota_preference_with_metadata` + interceptor in new development instead of the `post_update_quota_preference` interceptor. + When both interceptors are used, this `post_update_quota_preference_with_metadata` interceptor runs after the + `post_update_quota_preference` interceptor. The (possibly modified) response returned by + `post_update_quota_preference` will be passed to + `post_update_quota_preference_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CloudQuotasRestStub: @@ -500,6 +643,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -647,6 +794,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_quota_info(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_quota_info_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -795,6 +946,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -940,6 +1095,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_quota_infos(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_quota_infos_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1087,6 +1246,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_quota_preferences(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_quota_preferences_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1244,6 +1407,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_quota_preference(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_quota_preference_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/client.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/client.py index 2618374b1be9..a828b0570fc6 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/client.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -499,6 +501,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/transports/rest.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/transports/rest.py index 4fc463427378..ee1e5d86cdd4 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/transports/rest.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/services/quota_adjuster_settings_manager/transports/rest.py @@ -113,12 +113,38 @@ def post_get_quota_adjuster_settings( ) -> quota_adjuster_settings.QuotaAdjusterSettings: """Post-rpc interceptor for get_quota_adjuster_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_quota_adjuster_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the QuotaAdjusterSettingsManager server but before - it is returned to user code. + it is returned to user code. This `post_get_quota_adjuster_settings` interceptor runs + before the `post_get_quota_adjuster_settings_with_metadata` interceptor. """ return response + def post_get_quota_adjuster_settings_with_metadata( + self, + response: quota_adjuster_settings.QuotaAdjusterSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + quota_adjuster_settings.QuotaAdjusterSettings, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_quota_adjuster_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the QuotaAdjusterSettingsManager server but before it is returned to user code. + + We recommend only using this `post_get_quota_adjuster_settings_with_metadata` + interceptor in new development instead of the `post_get_quota_adjuster_settings` interceptor. + When both interceptors are used, this `post_get_quota_adjuster_settings_with_metadata` interceptor runs after the + `post_get_quota_adjuster_settings` interceptor. The (possibly modified) response returned by + `post_get_quota_adjuster_settings` will be passed to + `post_get_quota_adjuster_settings_with_metadata`. + """ + return response, metadata + def pre_update_quota_adjuster_settings( self, request: gac_quota_adjuster_settings.UpdateQuotaAdjusterSettingsRequest, @@ -139,12 +165,38 @@ def post_update_quota_adjuster_settings( ) -> gac_quota_adjuster_settings.QuotaAdjusterSettings: """Post-rpc interceptor for update_quota_adjuster_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_quota_adjuster_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the QuotaAdjusterSettingsManager server but before - it is returned to user code. + it is returned to user code. This `post_update_quota_adjuster_settings` interceptor runs + before the `post_update_quota_adjuster_settings_with_metadata` interceptor. """ return response + def post_update_quota_adjuster_settings_with_metadata( + self, + response: gac_quota_adjuster_settings.QuotaAdjusterSettings, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gac_quota_adjuster_settings.QuotaAdjusterSettings, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_quota_adjuster_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the QuotaAdjusterSettingsManager server but before it is returned to user code. + + We recommend only using this `post_update_quota_adjuster_settings_with_metadata` + interceptor in new development instead of the `post_update_quota_adjuster_settings` interceptor. + When both interceptors are used, this `post_update_quota_adjuster_settings_with_metadata` interceptor runs after the + `post_update_quota_adjuster_settings` interceptor. The (possibly modified) response returned by + `post_update_quota_adjuster_settings` will be passed to + `post_update_quota_adjuster_settings_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class QuotaAdjusterSettingsManagerRestStub: @@ -366,6 +418,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_quota_adjuster_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_quota_adjuster_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -524,6 +580,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_quota_adjuster_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_quota_adjuster_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-quotas/noxfile.py b/packages/google-cloud-quotas/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-quotas/noxfile.py +++ b/packages/google-cloud-quotas/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json index 023e6530a69d..5c9d0867f7f3 100644 --- a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json +++ b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-quotas", - "version": "0.1.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json index 4cdf9d25d697..785a0e000fa7 100644 --- a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json +++ b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-quotas", - "version": "0.1.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1/test_cloud_quotas.py b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1/test_cloud_quotas.py index 9e5844a0259d..d4490c21688e 100644 --- a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1/test_cloud_quotas.py +++ b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1/test_cloud_quotas.py @@ -63,6 +63,13 @@ ) from google.cloud.cloudquotas_v1.types import cloudquotas, resources +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -302,6 +309,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudQuotasClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudQuotasClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5448,10 +5498,13 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_list_quota_infos" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_list_quota_infos_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_list_quota_infos" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.ListQuotaInfosRequest.pb( cloudquotas.ListQuotaInfosRequest() ) @@ -5477,6 +5530,7 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudquotas.ListQuotaInfosResponse() + post_with_metadata.return_value = cloudquotas.ListQuotaInfosResponse(), metadata client.list_quota_infos( request, @@ -5488,6 +5542,7 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_quota_info_rest_bad_request(request_type=cloudquotas.GetQuotaInfoRequest): @@ -5600,10 +5655,13 @@ def test_get_quota_info_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_get_quota_info" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_get_quota_info_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_get_quota_info" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.GetQuotaInfoRequest.pb( cloudquotas.GetQuotaInfoRequest() ) @@ -5627,6 +5685,7 @@ def test_get_quota_info_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaInfo() + post_with_metadata.return_value = resources.QuotaInfo(), metadata client.get_quota_info( request, @@ -5638,6 +5697,7 @@ def test_get_quota_info_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_quota_preferences_rest_bad_request( @@ -5724,10 +5784,14 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_list_quota_preferences" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_list_quota_preferences_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_list_quota_preferences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.ListQuotaPreferencesRequest.pb( cloudquotas.ListQuotaPreferencesRequest() ) @@ -5753,6 +5817,10 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudquotas.ListQuotaPreferencesResponse() + post_with_metadata.return_value = ( + cloudquotas.ListQuotaPreferencesResponse(), + metadata, + ) client.list_quota_preferences( request, @@ -5764,6 +5832,7 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_quota_preference_rest_bad_request( @@ -5864,10 +5933,13 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_get_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_get_quota_preference_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_get_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.GetQuotaPreferenceRequest.pb( cloudquotas.GetQuotaPreferenceRequest() ) @@ -5891,6 +5963,7 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.get_quota_preference( request, @@ -5902,6 +5975,7 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_quota_preference_rest_bad_request( @@ -6087,10 +6161,14 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_create_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_create_quota_preference_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_create_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.CreateQuotaPreferenceRequest.pb( cloudquotas.CreateQuotaPreferenceRequest() ) @@ -6114,6 +6192,7 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.create_quota_preference( request, @@ -6125,6 +6204,7 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_quota_preference_rest_bad_request( @@ -6318,10 +6398,14 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_update_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_update_quota_preference_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_update_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.UpdateQuotaPreferenceRequest.pb( cloudquotas.UpdateQuotaPreferenceRequest() ) @@ -6345,6 +6429,7 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.update_quota_preference( request, @@ -6356,6 +6441,7 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_cloud_quotas.py b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_cloud_quotas.py index a88f3ba5bbf6..f43317deddc5 100644 --- a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_cloud_quotas.py +++ b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_cloud_quotas.py @@ -63,6 +63,13 @@ ) from google.cloud.cloudquotas_v1beta.types import cloudquotas, resources +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -302,6 +309,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudQuotasClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudQuotasClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5448,10 +5498,13 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_list_quota_infos" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_list_quota_infos_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_list_quota_infos" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.ListQuotaInfosRequest.pb( cloudquotas.ListQuotaInfosRequest() ) @@ -5477,6 +5530,7 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudquotas.ListQuotaInfosResponse() + post_with_metadata.return_value = cloudquotas.ListQuotaInfosResponse(), metadata client.list_quota_infos( request, @@ -5488,6 +5542,7 @@ def test_list_quota_infos_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_quota_info_rest_bad_request(request_type=cloudquotas.GetQuotaInfoRequest): @@ -5600,10 +5655,13 @@ def test_get_quota_info_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_get_quota_info" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_get_quota_info_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_get_quota_info" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.GetQuotaInfoRequest.pb( cloudquotas.GetQuotaInfoRequest() ) @@ -5627,6 +5685,7 @@ def test_get_quota_info_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaInfo() + post_with_metadata.return_value = resources.QuotaInfo(), metadata client.get_quota_info( request, @@ -5638,6 +5697,7 @@ def test_get_quota_info_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_quota_preferences_rest_bad_request( @@ -5724,10 +5784,14 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_list_quota_preferences" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_list_quota_preferences_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_list_quota_preferences" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.ListQuotaPreferencesRequest.pb( cloudquotas.ListQuotaPreferencesRequest() ) @@ -5753,6 +5817,10 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudquotas.ListQuotaPreferencesResponse() + post_with_metadata.return_value = ( + cloudquotas.ListQuotaPreferencesResponse(), + metadata, + ) client.list_quota_preferences( request, @@ -5764,6 +5832,7 @@ def test_list_quota_preferences_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_quota_preference_rest_bad_request( @@ -5864,10 +5933,13 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_get_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, "post_get_quota_preference_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_get_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.GetQuotaPreferenceRequest.pb( cloudquotas.GetQuotaPreferenceRequest() ) @@ -5891,6 +5963,7 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.get_quota_preference( request, @@ -5902,6 +5975,7 @@ def test_get_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_quota_preference_rest_bad_request( @@ -6087,10 +6161,14 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_create_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_create_quota_preference_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_create_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.CreateQuotaPreferenceRequest.pb( cloudquotas.CreateQuotaPreferenceRequest() ) @@ -6114,6 +6192,7 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.create_quota_preference( request, @@ -6125,6 +6204,7 @@ def test_create_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_quota_preference_rest_bad_request( @@ -6318,10 +6398,14 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudQuotasRestInterceptor, "post_update_quota_preference" ) as post, mock.patch.object( + transports.CloudQuotasRestInterceptor, + "post_update_quota_preference_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudQuotasRestInterceptor, "pre_update_quota_preference" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudquotas.UpdateQuotaPreferenceRequest.pb( cloudquotas.UpdateQuotaPreferenceRequest() ) @@ -6345,6 +6429,7 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resources.QuotaPreference() + post_with_metadata.return_value = resources.QuotaPreference(), metadata client.update_quota_preference( request, @@ -6356,6 +6441,7 @@ def test_update_quota_preference_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_quota_adjuster_settings_manager.py b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_quota_adjuster_settings_manager.py index 1141de8a8476..7545a1bdba3a 100644 --- a/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_quota_adjuster_settings_manager.py +++ b/packages/google-cloud-quotas/tests/unit/gapic/cloudquotas_v1beta/test_quota_adjuster_settings_manager.py @@ -64,6 +64,13 @@ ) from google.cloud.cloudquotas_v1beta.types import quota_adjuster_settings +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -349,6 +356,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = QuotaAdjusterSettingsManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = QuotaAdjusterSettingsManagerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2689,11 +2739,15 @@ def test_update_quota_adjuster_settings_rest_interceptors(null_interceptor): transports.QuotaAdjusterSettingsManagerRestInterceptor, "post_update_quota_adjuster_settings", ) as post, mock.patch.object( + transports.QuotaAdjusterSettingsManagerRestInterceptor, + "post_update_quota_adjuster_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.QuotaAdjusterSettingsManagerRestInterceptor, "pre_update_quota_adjuster_settings", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = gac_quota_adjuster_settings.UpdateQuotaAdjusterSettingsRequest.pb( gac_quota_adjuster_settings.UpdateQuotaAdjusterSettingsRequest() ) @@ -2719,6 +2773,10 @@ def test_update_quota_adjuster_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gac_quota_adjuster_settings.QuotaAdjusterSettings() + post_with_metadata.return_value = ( + gac_quota_adjuster_settings.QuotaAdjusterSettings(), + metadata, + ) client.update_quota_adjuster_settings( request, @@ -2730,6 +2788,7 @@ def test_update_quota_adjuster_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_quota_adjuster_settings_rest_bad_request( @@ -2822,11 +2881,15 @@ def test_get_quota_adjuster_settings_rest_interceptors(null_interceptor): transports.QuotaAdjusterSettingsManagerRestInterceptor, "post_get_quota_adjuster_settings", ) as post, mock.patch.object( + transports.QuotaAdjusterSettingsManagerRestInterceptor, + "post_get_quota_adjuster_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.QuotaAdjusterSettingsManagerRestInterceptor, "pre_get_quota_adjuster_settings", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = quota_adjuster_settings.GetQuotaAdjusterSettingsRequest.pb( quota_adjuster_settings.GetQuotaAdjusterSettingsRequest() ) @@ -2852,6 +2915,10 @@ def test_get_quota_adjuster_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = quota_adjuster_settings.QuotaAdjusterSettings() + post_with_metadata.return_value = ( + quota_adjuster_settings.QuotaAdjusterSettings(), + metadata, + ) client.get_quota_adjuster_settings( request, @@ -2863,6 +2930,7 @@ def test_get_quota_adjuster_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-rapidmigrationassessment/README.rst b/packages/google-cloud-rapidmigrationassessment/README.rst index b071b480ec38..e1a8556ac503 100644 --- a/packages/google-cloud-rapidmigrationassessment/README.rst +++ b/packages/google-cloud-rapidmigrationassessment/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Rapid Migration Assessment API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Rapid Migration Assessment API.: https://cloud.google.com/migration-center/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py index 17bbab4c1877..558c8aab67c5 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.12" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/client.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/client.py index 8ccacf2ddd65..04c936c161d5 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/client.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -522,6 +524,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1992,16 +2021,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2047,16 +2080,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -2213,16 +2250,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2268,16 +2309,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/transports/rest.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/transports/rest.py index 714507957c5a..e970eb2a2515 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/transports/rest.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/services/rapid_migration_assessment/transports/rest.py @@ -179,12 +179,35 @@ def post_create_annotation( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_annotation - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_annotation_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_create_annotation` interceptor runs + before the `post_create_annotation_with_metadata` interceptor. """ return response + def post_create_annotation_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_annotation + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_create_annotation_with_metadata` + interceptor in new development instead of the `post_create_annotation` interceptor. + When both interceptors are used, this `post_create_annotation_with_metadata` interceptor runs after the + `post_create_annotation` interceptor. The (possibly modified) response returned by + `post_create_annotation` will be passed to + `post_create_annotation_with_metadata`. + """ + return response, metadata + def pre_create_collector( self, request: rapidmigrationassessment.CreateCollectorRequest, @@ -205,12 +228,35 @@ def post_create_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_create_collector` interceptor runs + before the `post_create_collector_with_metadata` interceptor. """ return response + def post_create_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_create_collector_with_metadata` + interceptor in new development instead of the `post_create_collector` interceptor. + When both interceptors are used, this `post_create_collector_with_metadata` interceptor runs after the + `post_create_collector` interceptor. The (possibly modified) response returned by + `post_create_collector` will be passed to + `post_create_collector_with_metadata`. + """ + return response, metadata + def pre_delete_collector( self, request: rapidmigrationassessment.DeleteCollectorRequest, @@ -231,12 +277,35 @@ def post_delete_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_delete_collector` interceptor runs + before the `post_delete_collector_with_metadata` interceptor. """ return response + def post_delete_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_delete_collector_with_metadata` + interceptor in new development instead of the `post_delete_collector` interceptor. + When both interceptors are used, this `post_delete_collector_with_metadata` interceptor runs after the + `post_delete_collector` interceptor. The (possibly modified) response returned by + `post_delete_collector` will be passed to + `post_delete_collector_with_metadata`. + """ + return response, metadata + def pre_get_annotation( self, request: rapidmigrationassessment.GetAnnotationRequest, @@ -257,12 +326,35 @@ def post_get_annotation( ) -> api_entities.Annotation: """Post-rpc interceptor for get_annotation - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_annotation_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_get_annotation` interceptor runs + before the `post_get_annotation_with_metadata` interceptor. """ return response + def post_get_annotation_with_metadata( + self, + response: api_entities.Annotation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[api_entities.Annotation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_annotation + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_get_annotation_with_metadata` + interceptor in new development instead of the `post_get_annotation` interceptor. + When both interceptors are used, this `post_get_annotation_with_metadata` interceptor runs after the + `post_get_annotation` interceptor. The (possibly modified) response returned by + `post_get_annotation` will be passed to + `post_get_annotation_with_metadata`. + """ + return response, metadata + def pre_get_collector( self, request: rapidmigrationassessment.GetCollectorRequest, @@ -283,12 +375,35 @@ def post_get_collector( ) -> api_entities.Collector: """Post-rpc interceptor for get_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_get_collector` interceptor runs + before the `post_get_collector_with_metadata` interceptor. """ return response + def post_get_collector_with_metadata( + self, + response: api_entities.Collector, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[api_entities.Collector, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_get_collector_with_metadata` + interceptor in new development instead of the `post_get_collector` interceptor. + When both interceptors are used, this `post_get_collector_with_metadata` interceptor runs after the + `post_get_collector` interceptor. The (possibly modified) response returned by + `post_get_collector` will be passed to + `post_get_collector_with_metadata`. + """ + return response, metadata + def pre_list_collectors( self, request: rapidmigrationassessment.ListCollectorsRequest, @@ -309,12 +424,38 @@ def post_list_collectors( ) -> rapidmigrationassessment.ListCollectorsResponse: """Post-rpc interceptor for list_collectors - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_collectors_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_list_collectors` interceptor runs + before the `post_list_collectors_with_metadata` interceptor. """ return response + def post_list_collectors_with_metadata( + self, + response: rapidmigrationassessment.ListCollectorsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + rapidmigrationassessment.ListCollectorsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_collectors + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_list_collectors_with_metadata` + interceptor in new development instead of the `post_list_collectors` interceptor. + When both interceptors are used, this `post_list_collectors_with_metadata` interceptor runs after the + `post_list_collectors` interceptor. The (possibly modified) response returned by + `post_list_collectors` will be passed to + `post_list_collectors_with_metadata`. + """ + return response, metadata + def pre_pause_collector( self, request: rapidmigrationassessment.PauseCollectorRequest, @@ -335,12 +476,35 @@ def post_pause_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for pause_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_pause_collector` interceptor runs + before the `post_pause_collector_with_metadata` interceptor. """ return response + def post_pause_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_pause_collector_with_metadata` + interceptor in new development instead of the `post_pause_collector` interceptor. + When both interceptors are used, this `post_pause_collector_with_metadata` interceptor runs after the + `post_pause_collector` interceptor. The (possibly modified) response returned by + `post_pause_collector` will be passed to + `post_pause_collector_with_metadata`. + """ + return response, metadata + def pre_register_collector( self, request: rapidmigrationassessment.RegisterCollectorRequest, @@ -361,12 +525,35 @@ def post_register_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for register_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_register_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_register_collector` interceptor runs + before the `post_register_collector_with_metadata` interceptor. """ return response + def post_register_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for register_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_register_collector_with_metadata` + interceptor in new development instead of the `post_register_collector` interceptor. + When both interceptors are used, this `post_register_collector_with_metadata` interceptor runs after the + `post_register_collector` interceptor. The (possibly modified) response returned by + `post_register_collector` will be passed to + `post_register_collector_with_metadata`. + """ + return response, metadata + def pre_resume_collector( self, request: rapidmigrationassessment.ResumeCollectorRequest, @@ -387,12 +574,35 @@ def post_resume_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for resume_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_resume_collector` interceptor runs + before the `post_resume_collector_with_metadata` interceptor. """ return response + def post_resume_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_resume_collector_with_metadata` + interceptor in new development instead of the `post_resume_collector` interceptor. + When both interceptors are used, this `post_resume_collector_with_metadata` interceptor runs after the + `post_resume_collector` interceptor. The (possibly modified) response returned by + `post_resume_collector` will be passed to + `post_resume_collector_with_metadata`. + """ + return response, metadata + def pre_update_collector( self, request: rapidmigrationassessment.UpdateCollectorRequest, @@ -413,12 +623,35 @@ def post_update_collector( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_collector - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_collector_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the RapidMigrationAssessment server but before - it is returned to user code. + it is returned to user code. This `post_update_collector` interceptor runs + before the `post_update_collector_with_metadata` interceptor. """ return response + def post_update_collector_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_collector + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the RapidMigrationAssessment server but before it is returned to user code. + + We recommend only using this `post_update_collector_with_metadata` + interceptor in new development instead of the `post_update_collector` interceptor. + When both interceptors are used, this `post_update_collector_with_metadata` interceptor runs after the + `post_update_collector` interceptor. The (possibly modified) response returned by + `post_update_collector` will be passed to + `post_update_collector_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -835,6 +1068,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_annotation(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_annotation_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -987,6 +1224,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1133,6 +1374,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1277,6 +1522,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_annotation(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_annotation_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1421,6 +1670,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1567,6 +1820,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_collectors(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_collectors_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1721,6 +1978,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1873,6 +2134,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_register_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_register_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2025,6 +2290,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2177,6 +2446,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_collector(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_collector_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-rapidmigrationassessment/noxfile.py b/packages/google-cloud-rapidmigrationassessment/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-rapidmigrationassessment/noxfile.py +++ b/packages/google-cloud-rapidmigrationassessment/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json b/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json index 5e2c82637365..2c00dccb6124 100644 --- a/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json +++ b/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-rapidmigrationassessment", - "version": "0.1.12" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-rapidmigrationassessment/tests/unit/gapic/rapidmigrationassessment_v1/test_rapid_migration_assessment.py b/packages/google-cloud-rapidmigrationassessment/tests/unit/gapic/rapidmigrationassessment_v1/test_rapid_migration_assessment.py index 78aa30177f24..e96434744c2f 100644 --- a/packages/google-cloud-rapidmigrationassessment/tests/unit/gapic/rapidmigrationassessment_v1/test_rapid_migration_assessment.py +++ b/packages/google-cloud-rapidmigrationassessment/tests/unit/gapic/rapidmigrationassessment_v1/test_rapid_migration_assessment.py @@ -76,6 +76,13 @@ rapidmigrationassessment, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -351,6 +358,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RapidMigrationAssessmentClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RapidMigrationAssessmentClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7488,10 +7538,14 @@ def test_create_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_create_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_create_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_create_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.CreateCollectorRequest.pb( rapidmigrationassessment.CreateCollectorRequest() ) @@ -7515,6 +7569,7 @@ def test_create_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_collector( request, @@ -7526,6 +7581,7 @@ def test_create_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_annotation_rest_bad_request( @@ -7682,10 +7738,14 @@ def test_create_annotation_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_create_annotation" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_create_annotation_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_create_annotation" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.CreateAnnotationRequest.pb( rapidmigrationassessment.CreateAnnotationRequest() ) @@ -7709,6 +7769,7 @@ def test_create_annotation_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_annotation( request, @@ -7720,6 +7781,7 @@ def test_create_annotation_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_annotation_rest_bad_request( @@ -7806,10 +7868,14 @@ def test_get_annotation_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_get_annotation" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_get_annotation_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_get_annotation" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.GetAnnotationRequest.pb( rapidmigrationassessment.GetAnnotationRequest() ) @@ -7833,6 +7899,7 @@ def test_get_annotation_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = api_entities.Annotation() + post_with_metadata.return_value = api_entities.Annotation(), metadata client.get_annotation( request, @@ -7844,6 +7911,7 @@ def test_get_annotation_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_collectors_rest_bad_request( @@ -7930,10 +7998,14 @@ def test_list_collectors_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_list_collectors" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_list_collectors_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_list_collectors" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.ListCollectorsRequest.pb( rapidmigrationassessment.ListCollectorsRequest() ) @@ -7959,6 +8031,10 @@ def test_list_collectors_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = rapidmigrationassessment.ListCollectorsResponse() + post_with_metadata.return_value = ( + rapidmigrationassessment.ListCollectorsResponse(), + metadata, + ) client.list_collectors( request, @@ -7970,6 +8046,7 @@ def test_list_collectors_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_collector_rest_bad_request( @@ -8072,10 +8149,14 @@ def test_get_collector_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_get_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_get_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_get_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.GetCollectorRequest.pb( rapidmigrationassessment.GetCollectorRequest() ) @@ -8099,6 +8180,7 @@ def test_get_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = api_entities.Collector() + post_with_metadata.return_value = api_entities.Collector(), metadata client.get_collector( request, @@ -8110,6 +8192,7 @@ def test_get_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_collector_rest_bad_request( @@ -8280,10 +8363,14 @@ def test_update_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_update_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_update_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_update_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.UpdateCollectorRequest.pb( rapidmigrationassessment.UpdateCollectorRequest() ) @@ -8307,6 +8394,7 @@ def test_update_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_collector( request, @@ -8318,6 +8406,7 @@ def test_update_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_collector_rest_bad_request( @@ -8398,10 +8487,14 @@ def test_delete_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_delete_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_delete_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_delete_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.DeleteCollectorRequest.pb( rapidmigrationassessment.DeleteCollectorRequest() ) @@ -8425,6 +8518,7 @@ def test_delete_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_collector( request, @@ -8436,6 +8530,7 @@ def test_delete_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_collector_rest_bad_request( @@ -8516,10 +8611,14 @@ def test_resume_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_resume_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_resume_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_resume_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.ResumeCollectorRequest.pb( rapidmigrationassessment.ResumeCollectorRequest() ) @@ -8543,6 +8642,7 @@ def test_resume_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.resume_collector( request, @@ -8554,6 +8654,7 @@ def test_resume_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_register_collector_rest_bad_request( @@ -8634,10 +8735,14 @@ def test_register_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_register_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_register_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_register_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.RegisterCollectorRequest.pb( rapidmigrationassessment.RegisterCollectorRequest() ) @@ -8661,6 +8766,7 @@ def test_register_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.register_collector( request, @@ -8672,6 +8778,7 @@ def test_register_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_pause_collector_rest_bad_request( @@ -8752,10 +8859,14 @@ def test_pause_collector_rest_interceptors(null_interceptor): ), mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "post_pause_collector" ) as post, mock.patch.object( + transports.RapidMigrationAssessmentRestInterceptor, + "post_pause_collector_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RapidMigrationAssessmentRestInterceptor, "pre_pause_collector" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = rapidmigrationassessment.PauseCollectorRequest.pb( rapidmigrationassessment.PauseCollectorRequest() ) @@ -8779,6 +8890,7 @@ def test_pause_collector_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.pause_collector( request, @@ -8790,6 +8902,7 @@ def test_pause_collector_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-recaptcha-enterprise/README.rst b/packages/google-cloud-recaptcha-enterprise/README.rst index 5a19245ba7a0..b8a766d7880c 100644 --- a/packages/google-cloud-recaptcha-enterprise/README.rst +++ b/packages/google-cloud-recaptcha-enterprise/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the reCAPTCHA Enterprise.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the reCAPTCHA Enterprise.: https://cloud.google.com/recaptcha-enterprise -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py index 5173b6c80b17..558c8aab67c5 100644 --- a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py +++ b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.26.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py index 5173b6c80b17..558c8aab67c5 100644 --- a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py +++ b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.26.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/services/recaptcha_enterprise_service/client.py b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/services/recaptcha_enterprise_service/client.py index 7dac0be6025a..34c25567bad4 100644 --- a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/services/recaptcha_enterprise_service/client.py +++ b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/services/recaptcha_enterprise_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -582,6 +584,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recaptcha-enterprise/noxfile.py b/packages/google-cloud-recaptcha-enterprise/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-recaptcha-enterprise/noxfile.py +++ b/packages/google-cloud-recaptcha-enterprise/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json b/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json index 091862e58ffc..78c7a5f19cbb 100644 --- a/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json +++ b/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recaptcha-enterprise", - "version": "1.26.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-recaptcha-enterprise/tests/unit/gapic/recaptchaenterprise_v1/test_recaptcha_enterprise_service.py b/packages/google-cloud-recaptcha-enterprise/tests/unit/gapic/recaptchaenterprise_v1/test_recaptcha_enterprise_service.py index 5f5ae43e9d4d..dfb7e41cf5d7 100644 --- a/packages/google-cloud-recaptcha-enterprise/tests/unit/gapic/recaptchaenterprise_v1/test_recaptcha_enterprise_service.py +++ b/packages/google-cloud-recaptcha-enterprise/tests/unit/gapic/recaptchaenterprise_v1/test_recaptcha_enterprise_service.py @@ -22,6 +22,7 @@ except ImportError: # pragma: NO COVER import mock +import json import math from google.api_core import api_core_version @@ -59,6 +60,13 @@ ) from google.cloud.recaptchaenterprise_v1.types import recaptchaenterprise +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RecaptchaEnterpriseServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RecaptchaEnterpriseServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ diff --git a/packages/google-cloud-recommendations-ai/README.rst b/packages/google-cloud-recommendations-ai/README.rst index 689ade69fd8e..6768ff1fb03e 100644 --- a/packages/google-cloud-recommendations-ai/README.rst +++ b/packages/google-cloud-recommendations-ai/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Recommendations AI.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Recommendations AI.: https://cloud.google.com/recommendations-ai/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py index 7008b740153b..558c8aab67c5 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.10.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py index 7008b740153b..558c8aab67c5 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.10.15" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/client.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/client.py index 07a6ee428d57..3be7ec8f0427 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/client.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -519,6 +521,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/rest.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/rest.py index 9acbdce0a671..3be1985aa242 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/rest.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/rest.py @@ -144,12 +144,35 @@ def post_create_catalog_item( ) -> catalog.CatalogItem: """Post-rpc interceptor for create_catalog_item - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_catalog_item_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_create_catalog_item` interceptor runs + before the `post_create_catalog_item_with_metadata` interceptor. """ return response + def post_create_catalog_item_with_metadata( + self, + response: catalog.CatalogItem, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CatalogItem, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_catalog_item + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_create_catalog_item_with_metadata` + interceptor in new development instead of the `post_create_catalog_item` interceptor. + When both interceptors are used, this `post_create_catalog_item_with_metadata` interceptor runs after the + `post_create_catalog_item` interceptor. The (possibly modified) response returned by + `post_create_catalog_item` will be passed to + `post_create_catalog_item_with_metadata`. + """ + return response, metadata + def pre_delete_catalog_item( self, request: catalog_service.DeleteCatalogItemRequest, @@ -184,12 +207,35 @@ def post_get_catalog_item( ) -> catalog.CatalogItem: """Post-rpc interceptor for get_catalog_item - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_catalog_item_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_catalog_item` interceptor runs + before the `post_get_catalog_item_with_metadata` interceptor. """ return response + def post_get_catalog_item_with_metadata( + self, + response: catalog.CatalogItem, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CatalogItem, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_catalog_item + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_catalog_item_with_metadata` + interceptor in new development instead of the `post_get_catalog_item` interceptor. + When both interceptors are used, this `post_get_catalog_item_with_metadata` interceptor runs after the + `post_get_catalog_item` interceptor. The (possibly modified) response returned by + `post_get_catalog_item` will be passed to + `post_get_catalog_item_with_metadata`. + """ + return response, metadata + def pre_import_catalog_items( self, request: import_.ImportCatalogItemsRequest, @@ -209,12 +255,35 @@ def post_import_catalog_items( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_catalog_items - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_catalog_items_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_import_catalog_items` interceptor runs + before the `post_import_catalog_items_with_metadata` interceptor. """ return response + def post_import_catalog_items_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_catalog_items + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_import_catalog_items_with_metadata` + interceptor in new development instead of the `post_import_catalog_items` interceptor. + When both interceptors are used, this `post_import_catalog_items_with_metadata` interceptor runs after the + `post_import_catalog_items` interceptor. The (possibly modified) response returned by + `post_import_catalog_items` will be passed to + `post_import_catalog_items_with_metadata`. + """ + return response, metadata + def pre_list_catalog_items( self, request: catalog_service.ListCatalogItemsRequest, @@ -234,12 +303,38 @@ def post_list_catalog_items( ) -> catalog_service.ListCatalogItemsResponse: """Post-rpc interceptor for list_catalog_items - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_catalog_items_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_list_catalog_items` interceptor runs + before the `post_list_catalog_items_with_metadata` interceptor. """ return response + def post_list_catalog_items_with_metadata( + self, + response: catalog_service.ListCatalogItemsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.ListCatalogItemsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_catalog_items + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_list_catalog_items_with_metadata` + interceptor in new development instead of the `post_list_catalog_items` interceptor. + When both interceptors are used, this `post_list_catalog_items_with_metadata` interceptor runs after the + `post_list_catalog_items` interceptor. The (possibly modified) response returned by + `post_list_catalog_items` will be passed to + `post_list_catalog_items_with_metadata`. + """ + return response, metadata + def pre_update_catalog_item( self, request: catalog_service.UpdateCatalogItemRequest, @@ -260,12 +355,35 @@ def post_update_catalog_item( ) -> catalog.CatalogItem: """Post-rpc interceptor for update_catalog_item - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_catalog_item_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_catalog_item` interceptor runs + before the `post_update_catalog_item_with_metadata` interceptor. """ return response + def post_update_catalog_item_with_metadata( + self, + response: catalog.CatalogItem, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CatalogItem, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_catalog_item + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_catalog_item_with_metadata` + interceptor in new development instead of the `post_update_catalog_item` interceptor. + When both interceptors are used, this `post_update_catalog_item_with_metadata` interceptor runs after the + `post_update_catalog_item` interceptor. The (possibly modified) response returned by + `post_update_catalog_item` will be passed to + `post_update_catalog_item_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CatalogServiceRestStub: @@ -531,6 +649,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_catalog_item(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_catalog_item_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -785,6 +907,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_catalog_item(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_catalog_item_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -934,6 +1060,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_catalog_items(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_catalog_items_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1079,6 +1209,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_catalog_items(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_catalog_items_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1232,6 +1366,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_catalog_item(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_catalog_item_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/client.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/client.py index 036d80331e7d..ef5b0968c3cf 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/client.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -524,6 +526,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/rest.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/rest.py index 2258b1f82b3a..a3361a34e546 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/rest.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/rest.py @@ -117,12 +117,38 @@ def post_create_prediction_api_key_registration( ) -> prediction_apikey_registry_service.PredictionApiKeyRegistration: """Post-rpc interceptor for create_prediction_api_key_registration - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_prediction_api_key_registration_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionApiKeyRegistry server but before - it is returned to user code. + it is returned to user code. This `post_create_prediction_api_key_registration` interceptor runs + before the `post_create_prediction_api_key_registration_with_metadata` interceptor. """ return response + def post_create_prediction_api_key_registration_with_metadata( + self, + response: prediction_apikey_registry_service.PredictionApiKeyRegistration, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_apikey_registry_service.PredictionApiKeyRegistration, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for create_prediction_api_key_registration + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionApiKeyRegistry server but before it is returned to user code. + + We recommend only using this `post_create_prediction_api_key_registration_with_metadata` + interceptor in new development instead of the `post_create_prediction_api_key_registration` interceptor. + When both interceptors are used, this `post_create_prediction_api_key_registration_with_metadata` interceptor runs after the + `post_create_prediction_api_key_registration` interceptor. The (possibly modified) response returned by + `post_create_prediction_api_key_registration` will be passed to + `post_create_prediction_api_key_registration_with_metadata`. + """ + return response, metadata + def pre_delete_prediction_api_key_registration( self, request: prediction_apikey_registry_service.DeletePredictionApiKeyRegistrationRequest, @@ -159,12 +185,38 @@ def post_list_prediction_api_key_registrations( ) -> prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse: """Post-rpc interceptor for list_prediction_api_key_registrations - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_prediction_api_key_registrations_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionApiKeyRegistry server but before - it is returned to user code. + it is returned to user code. This `post_list_prediction_api_key_registrations` interceptor runs + before the `post_list_prediction_api_key_registrations_with_metadata` interceptor. """ return response + def post_list_prediction_api_key_registrations_with_metadata( + self, + response: prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_prediction_api_key_registrations + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionApiKeyRegistry server but before it is returned to user code. + + We recommend only using this `post_list_prediction_api_key_registrations_with_metadata` + interceptor in new development instead of the `post_list_prediction_api_key_registrations` interceptor. + When both interceptors are used, this `post_list_prediction_api_key_registrations_with_metadata` interceptor runs after the + `post_list_prediction_api_key_registrations` interceptor. The (possibly modified) response returned by + `post_list_prediction_api_key_registrations` will be passed to + `post_list_prediction_api_key_registrations_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PredictionApiKeyRegistryRestStub: @@ -392,6 +444,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_prediction_api_key_registration(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_create_prediction_api_key_registration_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -668,6 +727,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_prediction_api_key_registrations(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_prediction_api_key_registrations_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/client.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/client.py index 3156b065fbe6..6af2a945758e 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/client.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -489,6 +491,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/rest.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/rest.py index bd23c1b1b54c..e546dcf7a9ad 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/rest.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/rest.py @@ -101,12 +101,37 @@ def post_predict( ) -> prediction_service.PredictResponse: """Post-rpc interceptor for predict - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_predict_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionService server but before - it is returned to user code. + it is returned to user code. This `post_predict` interceptor runs + before the `post_predict_with_metadata` interceptor. """ return response + def post_predict_with_metadata( + self, + response: prediction_service.PredictResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_service.PredictResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for predict + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionService server but before it is returned to user code. + + We recommend only using this `post_predict_with_metadata` + interceptor in new development instead of the `post_predict` interceptor. + When both interceptors are used, this `post_predict_with_metadata` interceptor runs after the + `post_predict` interceptor. The (possibly modified) response returned by + `post_predict` will be passed to + `post_predict_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class PredictionServiceRestStub: @@ -321,6 +346,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_predict(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_predict_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/client.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/client.py index 3b8ec2844e8d..222b7ac3b930 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/client.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -497,6 +499,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/rest.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/rest.py index 2808d40aa592..b42955c00943 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/rest.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/rest.py @@ -138,12 +138,35 @@ def post_collect_user_event( ) -> httpbody_pb2.HttpBody: """Post-rpc interceptor for collect_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_collect_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_collect_user_event` interceptor runs + before the `post_collect_user_event_with_metadata` interceptor. """ return response + def post_collect_user_event_with_metadata( + self, + response: httpbody_pb2.HttpBody, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[httpbody_pb2.HttpBody, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for collect_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_collect_user_event_with_metadata` + interceptor in new development instead of the `post_collect_user_event` interceptor. + When both interceptors are used, this `post_collect_user_event_with_metadata` interceptor runs after the + `post_collect_user_event` interceptor. The (possibly modified) response returned by + `post_collect_user_event` will be passed to + `post_collect_user_event_with_metadata`. + """ + return response, metadata + def pre_import_user_events( self, request: import_.ImportUserEventsRequest, @@ -163,12 +186,35 @@ def post_import_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_import_user_events` interceptor runs + before the `post_import_user_events_with_metadata` interceptor. """ return response + def post_import_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_import_user_events_with_metadata` + interceptor in new development instead of the `post_import_user_events` interceptor. + When both interceptors are used, this `post_import_user_events_with_metadata` interceptor runs after the + `post_import_user_events` interceptor. The (possibly modified) response returned by + `post_import_user_events` will be passed to + `post_import_user_events_with_metadata`. + """ + return response, metadata + def pre_list_user_events( self, request: user_event_service.ListUserEventsRequest, @@ -189,12 +235,38 @@ def post_list_user_events( ) -> user_event_service.ListUserEventsResponse: """Post-rpc interceptor for list_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_list_user_events` interceptor runs + before the `post_list_user_events_with_metadata` interceptor. """ return response + def post_list_user_events_with_metadata( + self, + response: user_event_service.ListUserEventsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + user_event_service.ListUserEventsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_list_user_events_with_metadata` + interceptor in new development instead of the `post_list_user_events` interceptor. + When both interceptors are used, this `post_list_user_events_with_metadata` interceptor runs after the + `post_list_user_events` interceptor. The (possibly modified) response returned by + `post_list_user_events` will be passed to + `post_list_user_events_with_metadata`. + """ + return response, metadata + def pre_purge_user_events( self, request: user_event_service.PurgeUserEventsRequest, @@ -215,12 +287,35 @@ def post_purge_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_purge_user_events` interceptor runs + before the `post_purge_user_events_with_metadata` interceptor. """ return response + def post_purge_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_purge_user_events_with_metadata` + interceptor in new development instead of the `post_purge_user_events` interceptor. + When both interceptors are used, this `post_purge_user_events_with_metadata` interceptor runs after the + `post_purge_user_events` interceptor. The (possibly modified) response returned by + `post_purge_user_events` will be passed to + `post_purge_user_events_with_metadata`. + """ + return response, metadata + def pre_write_user_event( self, request: user_event_service.WriteUserEventRequest, @@ -241,12 +336,35 @@ def post_write_user_event( ) -> gcr_user_event.UserEvent: """Post-rpc interceptor for write_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_write_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_write_user_event` interceptor runs + before the `post_write_user_event_with_metadata` interceptor. """ return response + def post_write_user_event_with_metadata( + self, + response: gcr_user_event.UserEvent, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_user_event.UserEvent, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for write_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_write_user_event_with_metadata` + interceptor in new development instead of the `post_write_user_event` interceptor. + When both interceptors are used, this `post_write_user_event_with_metadata` interceptor runs after the + `post_write_user_event` interceptor. The (possibly modified) response returned by + `post_write_user_event` will be passed to + `post_write_user_event_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class UserEventServiceRestStub: @@ -554,6 +672,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_collect_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_collect_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -705,6 +827,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -850,6 +976,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1003,6 +1133,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1156,6 +1290,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_write_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_write_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommendations-ai/noxfile.py b/packages/google-cloud-recommendations-ai/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-recommendations-ai/noxfile.py +++ b/packages/google-cloud-recommendations-ai/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json b/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json index 55c2440a053e..d22dc88c7d5b 100644 --- a/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json +++ b/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommendations-ai", - "version": "0.10.15" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_catalog_service.py b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_catalog_service.py index 40a8e8d24f93..33fa06984ecd 100644 --- a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_catalog_service.py +++ b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_catalog_service.py @@ -78,6 +78,13 @@ user_event, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -336,6 +343,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5308,10 +5358,14 @@ def test_create_catalog_item_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_create_catalog_item" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_create_catalog_item_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_create_catalog_item" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.CreateCatalogItemRequest.pb( catalog_service.CreateCatalogItemRequest() ) @@ -5335,6 +5389,7 @@ def test_create_catalog_item_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CatalogItem() + post_with_metadata.return_value = catalog.CatalogItem(), metadata client.create_catalog_item( request, @@ -5346,6 +5401,7 @@ def test_create_catalog_item_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_catalog_item_rest_bad_request( @@ -5444,10 +5500,13 @@ def test_get_catalog_item_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_catalog_item" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_get_catalog_item_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_catalog_item" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetCatalogItemRequest.pb( catalog_service.GetCatalogItemRequest() ) @@ -5471,6 +5530,7 @@ def test_get_catalog_item_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CatalogItem() + post_with_metadata.return_value = catalog.CatalogItem(), metadata client.get_catalog_item( request, @@ -5482,6 +5542,7 @@ def test_get_catalog_item_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_catalog_items_rest_bad_request( @@ -5566,10 +5627,14 @@ def test_list_catalog_items_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_list_catalog_items" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_list_catalog_items_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_list_catalog_items" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ListCatalogItemsRequest.pb( catalog_service.ListCatalogItemsRequest() ) @@ -5595,6 +5660,10 @@ def test_list_catalog_items_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.ListCatalogItemsResponse() + post_with_metadata.return_value = ( + catalog_service.ListCatalogItemsResponse(), + metadata, + ) client.list_catalog_items( request, @@ -5606,6 +5675,7 @@ def test_list_catalog_items_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_catalog_item_rest_bad_request( @@ -5793,10 +5863,14 @@ def test_update_catalog_item_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_catalog_item" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_catalog_item_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_catalog_item" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCatalogItemRequest.pb( catalog_service.UpdateCatalogItemRequest() ) @@ -5820,6 +5894,7 @@ def test_update_catalog_item_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CatalogItem() + post_with_metadata.return_value = catalog.CatalogItem(), metadata client.update_catalog_item( request, @@ -5831,6 +5906,7 @@ def test_update_catalog_item_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_catalog_item_rest_bad_request( @@ -6024,10 +6100,14 @@ def test_import_catalog_items_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CatalogServiceRestInterceptor, "post_import_catalog_items" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_import_catalog_items_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_import_catalog_items" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_.ImportCatalogItemsRequest.pb( import_.ImportCatalogItemsRequest() ) @@ -6051,6 +6131,7 @@ def test_import_catalog_items_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_catalog_items( request, @@ -6062,6 +6143,7 @@ def test_import_catalog_items_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_api_key_registry.py b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_api_key_registry.py index e417cbeb6e91..080744e3ec75 100644 --- a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_api_key_registry.py +++ b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_api_key_registry.py @@ -62,6 +62,13 @@ prediction_apikey_registry_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PredictionApiKeyRegistryClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PredictionApiKeyRegistryClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3524,11 +3574,15 @@ def test_create_prediction_api_key_registration_rest_interceptors(null_intercept transports.PredictionApiKeyRegistryRestInterceptor, "post_create_prediction_api_key_registration", ) as post, mock.patch.object( + transports.PredictionApiKeyRegistryRestInterceptor, + "post_create_prediction_api_key_registration_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PredictionApiKeyRegistryRestInterceptor, "pre_create_prediction_api_key_registration", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_apikey_registry_service.CreatePredictionApiKeyRegistrationRequest.pb( prediction_apikey_registry_service.CreatePredictionApiKeyRegistrationRequest() ) @@ -3560,6 +3614,10 @@ def test_create_prediction_api_key_registration_rest_interceptors(null_intercept post.return_value = ( prediction_apikey_registry_service.PredictionApiKeyRegistration() ) + post_with_metadata.return_value = ( + prediction_apikey_registry_service.PredictionApiKeyRegistration(), + metadata, + ) client.create_prediction_api_key_registration( request, @@ -3571,6 +3629,7 @@ def test_create_prediction_api_key_registration_rest_interceptors(null_intercept pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_prediction_api_key_registrations_rest_bad_request( @@ -3662,11 +3721,15 @@ def test_list_prediction_api_key_registrations_rest_interceptors(null_intercepto transports.PredictionApiKeyRegistryRestInterceptor, "post_list_prediction_api_key_registrations", ) as post, mock.patch.object( + transports.PredictionApiKeyRegistryRestInterceptor, + "post_list_prediction_api_key_registrations_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.PredictionApiKeyRegistryRestInterceptor, "pre_list_prediction_api_key_registrations", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest.pb( prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest() ) @@ -3696,6 +3759,10 @@ def test_list_prediction_api_key_registrations_rest_interceptors(null_intercepto post.return_value = ( prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse() ) + post_with_metadata.return_value = ( + prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse(), + metadata, + ) client.list_prediction_api_key_registrations( request, @@ -3707,6 +3774,7 @@ def test_list_prediction_api_key_registrations_rest_interceptors(null_intercepto pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_prediction_api_key_registration_rest_bad_request( diff --git a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_service.py b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_service.py index 55224e7f9975..7e2f6a2ed0a7 100644 --- a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_service.py +++ b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_prediction_service.py @@ -67,6 +67,13 @@ ) from google.cloud.recommendationengine_v1beta1.types import user_event as gcr_user_event +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -334,6 +341,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2177,10 +2227,13 @@ def test_predict_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PredictionServiceRestInterceptor, "post_predict" ) as post, mock.patch.object( + transports.PredictionServiceRestInterceptor, "post_predict_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PredictionServiceRestInterceptor, "pre_predict" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_service.PredictRequest.pb( prediction_service.PredictRequest() ) @@ -2206,6 +2259,7 @@ def test_predict_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = prediction_service.PredictResponse() + post_with_metadata.return_value = prediction_service.PredictResponse(), metadata client.predict( request, @@ -2217,6 +2271,7 @@ def test_predict_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_user_event_service.py b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_user_event_service.py index c89712ecff86..62e97b3bec45 100644 --- a/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_user_event_service.py +++ b/packages/google-cloud-recommendations-ai/tests/unit/gapic/recommendationengine_v1beta1/test_user_event_service.py @@ -76,6 +76,13 @@ from google.cloud.recommendationengine_v1beta1.types import user_event from google.cloud.recommendationengine_v1beta1.types import user_event_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4790,10 +4840,14 @@ def test_write_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_write_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_write_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_write_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.WriteUserEventRequest.pb( user_event_service.WriteUserEventRequest() ) @@ -4817,6 +4871,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_user_event.UserEvent() + post_with_metadata.return_value = gcr_user_event.UserEvent(), metadata client.write_user_event( request, @@ -4828,6 +4883,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_collect_user_event_rest_bad_request( @@ -4915,10 +4971,14 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_collect_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_collect_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_collect_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.CollectUserEventRequest.pb( user_event_service.CollectUserEventRequest() ) @@ -4942,6 +5002,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = httpbody_pb2.HttpBody() + post_with_metadata.return_value = httpbody_pb2.HttpBody(), metadata client.collect_user_event( request, @@ -4953,6 +5014,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_user_events_rest_bad_request( @@ -5041,10 +5103,14 @@ def test_list_user_events_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_list_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_list_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_list_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.ListUserEventsRequest.pb( user_event_service.ListUserEventsRequest() ) @@ -5070,6 +5136,10 @@ def test_list_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user_event_service.ListUserEventsResponse() + post_with_metadata.return_value = ( + user_event_service.ListUserEventsResponse(), + metadata, + ) client.list_user_events( request, @@ -5081,6 +5151,7 @@ def test_list_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_purge_user_events_rest_bad_request( @@ -5165,10 +5236,14 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_purge_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_purge_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_purge_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.PurgeUserEventsRequest.pb( user_event_service.PurgeUserEventsRequest() ) @@ -5192,6 +5267,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_user_events( request, @@ -5203,6 +5279,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_user_events_rest_bad_request( @@ -5287,10 +5364,14 @@ def test_import_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_import_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_import_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_import_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_.ImportUserEventsRequest.pb( import_.ImportUserEventsRequest() ) @@ -5314,6 +5395,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_user_events( request, @@ -5325,6 +5407,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-recommender/README.rst b/packages/google-cloud-recommender/README.rst index 0973517bd995..2bf10bd71271 100644 --- a/packages/google-cloud-recommender/README.rst +++ b/packages/google-cloud-recommender/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Recommender.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Recommender.: https://cloud.google.com/recommender -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/client.py b/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/client.py index 1a4a9226790d..4515fff01bc6 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/client.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -618,6 +620,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/transports/rest.py b/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/transports/rest.py index 25b3a7928786..542ee8045f81 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/transports/rest.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1/services/recommender/transports/rest.py @@ -205,12 +205,35 @@ def pre_get_insight( def post_get_insight(self, response: insight.Insight) -> insight.Insight: """Post-rpc interceptor for get_insight - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_insight_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_insight` interceptor runs + before the `post_get_insight_with_metadata` interceptor. """ return response + def post_get_insight_with_metadata( + self, + response: insight.Insight, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[insight.Insight, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_insight + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_insight_with_metadata` + interceptor in new development instead of the `post_get_insight` interceptor. + When both interceptors are used, this `post_get_insight_with_metadata` interceptor runs after the + `post_get_insight` interceptor. The (possibly modified) response returned by + `post_get_insight` will be passed to + `post_get_insight_with_metadata`. + """ + return response, metadata + def pre_get_insight_type_config( self, request: recommender_service.GetInsightTypeConfigRequest, @@ -231,12 +254,37 @@ def post_get_insight_type_config( ) -> insight_type_config.InsightTypeConfig: """Post-rpc interceptor for get_insight_type_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_insight_type_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_insight_type_config` interceptor runs + before the `post_get_insight_type_config_with_metadata` interceptor. """ return response + def post_get_insight_type_config_with_metadata( + self, + response: insight_type_config.InsightTypeConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + insight_type_config.InsightTypeConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_insight_type_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_insight_type_config_with_metadata` + interceptor in new development instead of the `post_get_insight_type_config` interceptor. + When both interceptors are used, this `post_get_insight_type_config_with_metadata` interceptor runs after the + `post_get_insight_type_config` interceptor. The (possibly modified) response returned by + `post_get_insight_type_config` will be passed to + `post_get_insight_type_config_with_metadata`. + """ + return response, metadata + def pre_get_recommendation( self, request: recommender_service.GetRecommendationRequest, @@ -257,12 +305,35 @@ def post_get_recommendation( ) -> recommendation.Recommendation: """Post-rpc interceptor for get_recommendation - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_recommendation_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_recommendation` interceptor runs + before the `post_get_recommendation_with_metadata` interceptor. """ return response + def post_get_recommendation_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_recommendation + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_recommendation_with_metadata` + interceptor in new development instead of the `post_get_recommendation` interceptor. + When both interceptors are used, this `post_get_recommendation_with_metadata` interceptor runs after the + `post_get_recommendation` interceptor. The (possibly modified) response returned by + `post_get_recommendation` will be passed to + `post_get_recommendation_with_metadata`. + """ + return response, metadata + def pre_get_recommender_config( self, request: recommender_service.GetRecommenderConfigRequest, @@ -283,12 +354,37 @@ def post_get_recommender_config( ) -> recommender_config.RecommenderConfig: """Post-rpc interceptor for get_recommender_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_recommender_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_recommender_config` interceptor runs + before the `post_get_recommender_config_with_metadata` interceptor. """ return response + def post_get_recommender_config_with_metadata( + self, + response: recommender_config.RecommenderConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_config.RecommenderConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_recommender_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_recommender_config_with_metadata` + interceptor in new development instead of the `post_get_recommender_config` interceptor. + When both interceptors are used, this `post_get_recommender_config_with_metadata` interceptor runs after the + `post_get_recommender_config` interceptor. The (possibly modified) response returned by + `post_get_recommender_config` will be passed to + `post_get_recommender_config_with_metadata`. + """ + return response, metadata + def pre_list_insights( self, request: recommender_service.ListInsightsRequest, @@ -308,12 +404,38 @@ def post_list_insights( ) -> recommender_service.ListInsightsResponse: """Post-rpc interceptor for list_insights - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_insights_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_insights` interceptor runs + before the `post_list_insights_with_metadata` interceptor. """ return response + def post_list_insights_with_metadata( + self, + response: recommender_service.ListInsightsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListInsightsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_insights + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_insights_with_metadata` + interceptor in new development instead of the `post_list_insights` interceptor. + When both interceptors are used, this `post_list_insights_with_metadata` interceptor runs after the + `post_list_insights` interceptor. The (possibly modified) response returned by + `post_list_insights` will be passed to + `post_list_insights_with_metadata`. + """ + return response, metadata + def pre_list_recommendations( self, request: recommender_service.ListRecommendationsRequest, @@ -334,12 +456,38 @@ def post_list_recommendations( ) -> recommender_service.ListRecommendationsResponse: """Post-rpc interceptor for list_recommendations - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_recommendations_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_recommendations` interceptor runs + before the `post_list_recommendations_with_metadata` interceptor. """ return response + def post_list_recommendations_with_metadata( + self, + response: recommender_service.ListRecommendationsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListRecommendationsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_recommendations + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_recommendations_with_metadata` + interceptor in new development instead of the `post_list_recommendations` interceptor. + When both interceptors are used, this `post_list_recommendations_with_metadata` interceptor runs after the + `post_list_recommendations` interceptor. The (possibly modified) response returned by + `post_list_recommendations` will be passed to + `post_list_recommendations_with_metadata`. + """ + return response, metadata + def pre_mark_insight_accepted( self, request: recommender_service.MarkInsightAcceptedRequest, @@ -358,12 +506,35 @@ def pre_mark_insight_accepted( def post_mark_insight_accepted(self, response: insight.Insight) -> insight.Insight: """Post-rpc interceptor for mark_insight_accepted - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_insight_accepted_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_insight_accepted` interceptor runs + before the `post_mark_insight_accepted_with_metadata` interceptor. """ return response + def post_mark_insight_accepted_with_metadata( + self, + response: insight.Insight, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[insight.Insight, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_insight_accepted + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_insight_accepted_with_metadata` + interceptor in new development instead of the `post_mark_insight_accepted` interceptor. + When both interceptors are used, this `post_mark_insight_accepted_with_metadata` interceptor runs after the + `post_mark_insight_accepted` interceptor. The (possibly modified) response returned by + `post_mark_insight_accepted` will be passed to + `post_mark_insight_accepted_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_claimed( self, request: recommender_service.MarkRecommendationClaimedRequest, @@ -384,12 +555,35 @@ def post_mark_recommendation_claimed( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_claimed - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_claimed_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_claimed` interceptor runs + before the `post_mark_recommendation_claimed_with_metadata` interceptor. """ return response + def post_mark_recommendation_claimed_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_claimed + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_claimed_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_claimed` interceptor. + When both interceptors are used, this `post_mark_recommendation_claimed_with_metadata` interceptor runs after the + `post_mark_recommendation_claimed` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_claimed` will be passed to + `post_mark_recommendation_claimed_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_dismissed( self, request: recommender_service.MarkRecommendationDismissedRequest, @@ -410,12 +604,35 @@ def post_mark_recommendation_dismissed( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_dismissed - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_dismissed_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_dismissed` interceptor runs + before the `post_mark_recommendation_dismissed_with_metadata` interceptor. """ return response + def post_mark_recommendation_dismissed_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_dismissed + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_dismissed_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_dismissed` interceptor. + When both interceptors are used, this `post_mark_recommendation_dismissed_with_metadata` interceptor runs after the + `post_mark_recommendation_dismissed` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_dismissed` will be passed to + `post_mark_recommendation_dismissed_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_failed( self, request: recommender_service.MarkRecommendationFailedRequest, @@ -436,12 +653,35 @@ def post_mark_recommendation_failed( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_failed - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_failed_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_failed` interceptor runs + before the `post_mark_recommendation_failed_with_metadata` interceptor. """ return response + def post_mark_recommendation_failed_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_failed + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_failed_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_failed` interceptor. + When both interceptors are used, this `post_mark_recommendation_failed_with_metadata` interceptor runs after the + `post_mark_recommendation_failed` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_failed` will be passed to + `post_mark_recommendation_failed_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_succeeded( self, request: recommender_service.MarkRecommendationSucceededRequest, @@ -462,12 +702,35 @@ def post_mark_recommendation_succeeded( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_succeeded - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_succeeded_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_succeeded` interceptor runs + before the `post_mark_recommendation_succeeded_with_metadata` interceptor. """ return response + def post_mark_recommendation_succeeded_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_succeeded + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_succeeded_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_succeeded` interceptor. + When both interceptors are used, this `post_mark_recommendation_succeeded_with_metadata` interceptor runs after the + `post_mark_recommendation_succeeded` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_succeeded` will be passed to + `post_mark_recommendation_succeeded_with_metadata`. + """ + return response, metadata + def pre_update_insight_type_config( self, request: recommender_service.UpdateInsightTypeConfigRequest, @@ -488,12 +751,38 @@ def post_update_insight_type_config( ) -> gcr_insight_type_config.InsightTypeConfig: """Post-rpc interceptor for update_insight_type_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_insight_type_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_update_insight_type_config` interceptor runs + before the `post_update_insight_type_config_with_metadata` interceptor. """ return response + def post_update_insight_type_config_with_metadata( + self, + response: gcr_insight_type_config.InsightTypeConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_insight_type_config.InsightTypeConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_insight_type_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_update_insight_type_config_with_metadata` + interceptor in new development instead of the `post_update_insight_type_config` interceptor. + When both interceptors are used, this `post_update_insight_type_config_with_metadata` interceptor runs after the + `post_update_insight_type_config` interceptor. The (possibly modified) response returned by + `post_update_insight_type_config` will be passed to + `post_update_insight_type_config_with_metadata`. + """ + return response, metadata + def pre_update_recommender_config( self, request: recommender_service.UpdateRecommenderConfigRequest, @@ -514,12 +803,38 @@ def post_update_recommender_config( ) -> gcr_recommender_config.RecommenderConfig: """Post-rpc interceptor for update_recommender_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_recommender_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_update_recommender_config` interceptor runs + before the `post_update_recommender_config_with_metadata` interceptor. """ return response + def post_update_recommender_config_with_metadata( + self, + response: gcr_recommender_config.RecommenderConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_recommender_config.RecommenderConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_recommender_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_update_recommender_config_with_metadata` + interceptor in new development instead of the `post_update_recommender_config` interceptor. + When both interceptors are used, this `post_update_recommender_config_with_metadata` interceptor runs after the + `post_update_recommender_config` interceptor. The (possibly modified) response returned by + `post_update_recommender_config` will be passed to + `post_update_recommender_config_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class RecommenderRestStub: @@ -736,6 +1051,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_insight(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_insight_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -878,6 +1197,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_insight_type_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_insight_type_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1026,6 +1349,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_recommendation(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_recommendation_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1168,6 +1495,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_recommender_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_recommender_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1314,6 +1645,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_insights(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_insights_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1458,6 +1793,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_recommendations(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_recommendations_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1614,6 +1953,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_insight_accepted(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_insight_accepted_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1770,6 +2113,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_claimed(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_recommendation_claimed_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1926,6 +2273,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_dismissed(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_mark_recommendation_dismissed_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2079,6 +2433,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_failed(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_recommendation_failed_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2235,6 +2593,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_succeeded(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_mark_recommendation_succeeded_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2384,6 +2749,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_insight_type_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_insight_type_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2534,6 +2903,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_recommender_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_recommender_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/client.py b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/client.py index 611392db7047..1dd1cb19f66f 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/client.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -618,6 +620,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/transports/rest.py b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/transports/rest.py index 8d6380149d10..0980685b426f 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/transports/rest.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/services/recommender/transports/rest.py @@ -213,12 +213,35 @@ def pre_get_insight( def post_get_insight(self, response: insight.Insight) -> insight.Insight: """Post-rpc interceptor for get_insight - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_insight_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_insight` interceptor runs + before the `post_get_insight_with_metadata` interceptor. """ return response + def post_get_insight_with_metadata( + self, + response: insight.Insight, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[insight.Insight, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_insight + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_insight_with_metadata` + interceptor in new development instead of the `post_get_insight` interceptor. + When both interceptors are used, this `post_get_insight_with_metadata` interceptor runs after the + `post_get_insight` interceptor. The (possibly modified) response returned by + `post_get_insight` will be passed to + `post_get_insight_with_metadata`. + """ + return response, metadata + def pre_get_insight_type_config( self, request: recommender_service.GetInsightTypeConfigRequest, @@ -239,12 +262,37 @@ def post_get_insight_type_config( ) -> insight_type_config.InsightTypeConfig: """Post-rpc interceptor for get_insight_type_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_insight_type_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_insight_type_config` interceptor runs + before the `post_get_insight_type_config_with_metadata` interceptor. """ return response + def post_get_insight_type_config_with_metadata( + self, + response: insight_type_config.InsightTypeConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + insight_type_config.InsightTypeConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_insight_type_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_insight_type_config_with_metadata` + interceptor in new development instead of the `post_get_insight_type_config` interceptor. + When both interceptors are used, this `post_get_insight_type_config_with_metadata` interceptor runs after the + `post_get_insight_type_config` interceptor. The (possibly modified) response returned by + `post_get_insight_type_config` will be passed to + `post_get_insight_type_config_with_metadata`. + """ + return response, metadata + def pre_get_recommendation( self, request: recommender_service.GetRecommendationRequest, @@ -265,12 +313,35 @@ def post_get_recommendation( ) -> recommendation.Recommendation: """Post-rpc interceptor for get_recommendation - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_recommendation_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_recommendation` interceptor runs + before the `post_get_recommendation_with_metadata` interceptor. """ return response + def post_get_recommendation_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_recommendation + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_recommendation_with_metadata` + interceptor in new development instead of the `post_get_recommendation` interceptor. + When both interceptors are used, this `post_get_recommendation_with_metadata` interceptor runs after the + `post_get_recommendation` interceptor. The (possibly modified) response returned by + `post_get_recommendation` will be passed to + `post_get_recommendation_with_metadata`. + """ + return response, metadata + def pre_get_recommender_config( self, request: recommender_service.GetRecommenderConfigRequest, @@ -291,12 +362,37 @@ def post_get_recommender_config( ) -> recommender_config.RecommenderConfig: """Post-rpc interceptor for get_recommender_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_recommender_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_get_recommender_config` interceptor runs + before the `post_get_recommender_config_with_metadata` interceptor. """ return response + def post_get_recommender_config_with_metadata( + self, + response: recommender_config.RecommenderConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_config.RecommenderConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_recommender_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_get_recommender_config_with_metadata` + interceptor in new development instead of the `post_get_recommender_config` interceptor. + When both interceptors are used, this `post_get_recommender_config_with_metadata` interceptor runs after the + `post_get_recommender_config` interceptor. The (possibly modified) response returned by + `post_get_recommender_config` will be passed to + `post_get_recommender_config_with_metadata`. + """ + return response, metadata + def pre_list_insights( self, request: recommender_service.ListInsightsRequest, @@ -316,12 +412,38 @@ def post_list_insights( ) -> recommender_service.ListInsightsResponse: """Post-rpc interceptor for list_insights - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_insights_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_insights` interceptor runs + before the `post_list_insights_with_metadata` interceptor. """ return response + def post_list_insights_with_metadata( + self, + response: recommender_service.ListInsightsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListInsightsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_insights + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_insights_with_metadata` + interceptor in new development instead of the `post_list_insights` interceptor. + When both interceptors are used, this `post_list_insights_with_metadata` interceptor runs after the + `post_list_insights` interceptor. The (possibly modified) response returned by + `post_list_insights` will be passed to + `post_list_insights_with_metadata`. + """ + return response, metadata + def pre_list_insight_types( self, request: recommender_service.ListInsightTypesRequest, @@ -342,12 +464,38 @@ def post_list_insight_types( ) -> recommender_service.ListInsightTypesResponse: """Post-rpc interceptor for list_insight_types - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_insight_types_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_insight_types` interceptor runs + before the `post_list_insight_types_with_metadata` interceptor. """ return response + def post_list_insight_types_with_metadata( + self, + response: recommender_service.ListInsightTypesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListInsightTypesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_insight_types + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_insight_types_with_metadata` + interceptor in new development instead of the `post_list_insight_types` interceptor. + When both interceptors are used, this `post_list_insight_types_with_metadata` interceptor runs after the + `post_list_insight_types` interceptor. The (possibly modified) response returned by + `post_list_insight_types` will be passed to + `post_list_insight_types_with_metadata`. + """ + return response, metadata + def pre_list_recommendations( self, request: recommender_service.ListRecommendationsRequest, @@ -368,12 +516,38 @@ def post_list_recommendations( ) -> recommender_service.ListRecommendationsResponse: """Post-rpc interceptor for list_recommendations - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_recommendations_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_recommendations` interceptor runs + before the `post_list_recommendations_with_metadata` interceptor. """ return response + def post_list_recommendations_with_metadata( + self, + response: recommender_service.ListRecommendationsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListRecommendationsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_recommendations + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_recommendations_with_metadata` + interceptor in new development instead of the `post_list_recommendations` interceptor. + When both interceptors are used, this `post_list_recommendations_with_metadata` interceptor runs after the + `post_list_recommendations` interceptor. The (possibly modified) response returned by + `post_list_recommendations` will be passed to + `post_list_recommendations_with_metadata`. + """ + return response, metadata + def pre_list_recommenders( self, request: recommender_service.ListRecommendersRequest, @@ -394,12 +568,38 @@ def post_list_recommenders( ) -> recommender_service.ListRecommendersResponse: """Post-rpc interceptor for list_recommenders - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_recommenders_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_list_recommenders` interceptor runs + before the `post_list_recommenders_with_metadata` interceptor. """ return response + def post_list_recommenders_with_metadata( + self, + response: recommender_service.ListRecommendersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + recommender_service.ListRecommendersResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_recommenders + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_list_recommenders_with_metadata` + interceptor in new development instead of the `post_list_recommenders` interceptor. + When both interceptors are used, this `post_list_recommenders_with_metadata` interceptor runs after the + `post_list_recommenders` interceptor. The (possibly modified) response returned by + `post_list_recommenders` will be passed to + `post_list_recommenders_with_metadata`. + """ + return response, metadata + def pre_mark_insight_accepted( self, request: recommender_service.MarkInsightAcceptedRequest, @@ -418,12 +618,35 @@ def pre_mark_insight_accepted( def post_mark_insight_accepted(self, response: insight.Insight) -> insight.Insight: """Post-rpc interceptor for mark_insight_accepted - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_insight_accepted_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_insight_accepted` interceptor runs + before the `post_mark_insight_accepted_with_metadata` interceptor. """ return response + def post_mark_insight_accepted_with_metadata( + self, + response: insight.Insight, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[insight.Insight, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_insight_accepted + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_insight_accepted_with_metadata` + interceptor in new development instead of the `post_mark_insight_accepted` interceptor. + When both interceptors are used, this `post_mark_insight_accepted_with_metadata` interceptor runs after the + `post_mark_insight_accepted` interceptor. The (possibly modified) response returned by + `post_mark_insight_accepted` will be passed to + `post_mark_insight_accepted_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_claimed( self, request: recommender_service.MarkRecommendationClaimedRequest, @@ -444,12 +667,35 @@ def post_mark_recommendation_claimed( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_claimed - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_claimed_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_claimed` interceptor runs + before the `post_mark_recommendation_claimed_with_metadata` interceptor. """ return response + def post_mark_recommendation_claimed_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_claimed + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_claimed_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_claimed` interceptor. + When both interceptors are used, this `post_mark_recommendation_claimed_with_metadata` interceptor runs after the + `post_mark_recommendation_claimed` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_claimed` will be passed to + `post_mark_recommendation_claimed_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_failed( self, request: recommender_service.MarkRecommendationFailedRequest, @@ -470,12 +716,35 @@ def post_mark_recommendation_failed( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_failed - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_failed_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_failed` interceptor runs + before the `post_mark_recommendation_failed_with_metadata` interceptor. """ return response + def post_mark_recommendation_failed_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_failed + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_failed_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_failed` interceptor. + When both interceptors are used, this `post_mark_recommendation_failed_with_metadata` interceptor runs after the + `post_mark_recommendation_failed` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_failed` will be passed to + `post_mark_recommendation_failed_with_metadata`. + """ + return response, metadata + def pre_mark_recommendation_succeeded( self, request: recommender_service.MarkRecommendationSucceededRequest, @@ -496,12 +765,35 @@ def post_mark_recommendation_succeeded( ) -> recommendation.Recommendation: """Post-rpc interceptor for mark_recommendation_succeeded - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_mark_recommendation_succeeded_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_mark_recommendation_succeeded` interceptor runs + before the `post_mark_recommendation_succeeded_with_metadata` interceptor. """ return response + def post_mark_recommendation_succeeded_with_metadata( + self, + response: recommendation.Recommendation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[recommendation.Recommendation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for mark_recommendation_succeeded + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_mark_recommendation_succeeded_with_metadata` + interceptor in new development instead of the `post_mark_recommendation_succeeded` interceptor. + When both interceptors are used, this `post_mark_recommendation_succeeded_with_metadata` interceptor runs after the + `post_mark_recommendation_succeeded` interceptor. The (possibly modified) response returned by + `post_mark_recommendation_succeeded` will be passed to + `post_mark_recommendation_succeeded_with_metadata`. + """ + return response, metadata + def pre_update_insight_type_config( self, request: recommender_service.UpdateInsightTypeConfigRequest, @@ -522,12 +814,38 @@ def post_update_insight_type_config( ) -> gcr_insight_type_config.InsightTypeConfig: """Post-rpc interceptor for update_insight_type_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_insight_type_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_update_insight_type_config` interceptor runs + before the `post_update_insight_type_config_with_metadata` interceptor. """ return response + def post_update_insight_type_config_with_metadata( + self, + response: gcr_insight_type_config.InsightTypeConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_insight_type_config.InsightTypeConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_insight_type_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_update_insight_type_config_with_metadata` + interceptor in new development instead of the `post_update_insight_type_config` interceptor. + When both interceptors are used, this `post_update_insight_type_config_with_metadata` interceptor runs after the + `post_update_insight_type_config` interceptor. The (possibly modified) response returned by + `post_update_insight_type_config` will be passed to + `post_update_insight_type_config_with_metadata`. + """ + return response, metadata + def pre_update_recommender_config( self, request: recommender_service.UpdateRecommenderConfigRequest, @@ -548,12 +866,38 @@ def post_update_recommender_config( ) -> gcr_recommender_config.RecommenderConfig: """Post-rpc interceptor for update_recommender_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_recommender_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the Recommender server but before - it is returned to user code. + it is returned to user code. This `post_update_recommender_config` interceptor runs + before the `post_update_recommender_config_with_metadata` interceptor. """ return response + def post_update_recommender_config_with_metadata( + self, + response: gcr_recommender_config.RecommenderConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_recommender_config.RecommenderConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_recommender_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Recommender server but before it is returned to user code. + + We recommend only using this `post_update_recommender_config_with_metadata` + interceptor in new development instead of the `post_update_recommender_config` interceptor. + When both interceptors are used, this `post_update_recommender_config_with_metadata` interceptor runs after the + `post_update_recommender_config` interceptor. The (possibly modified) response returned by + `post_update_recommender_config` will be passed to + `post_update_recommender_config_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class RecommenderRestStub: @@ -770,6 +1114,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_insight(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_insight_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -912,6 +1260,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_insight_type_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_insight_type_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1060,6 +1412,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_recommendation(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_recommendation_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1202,6 +1558,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_recommender_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_recommender_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1348,6 +1708,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_insights(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_insights_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1492,6 +1856,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_insight_types(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_insight_types_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1636,6 +2004,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_recommendations(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_recommendations_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1782,6 +2154,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_recommenders(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_recommenders_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1936,6 +2312,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_insight_accepted(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_insight_accepted_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2092,6 +2472,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_claimed(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_recommendation_claimed_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2245,6 +2629,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_failed(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_mark_recommendation_failed_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2401,6 +2789,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_mark_recommendation_succeeded(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_mark_recommendation_succeeded_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2550,6 +2945,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_insight_type_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_insight_type_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2700,6 +3099,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_recommender_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_recommender_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-recommender/noxfile.py b/packages/google-cloud-recommender/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-recommender/noxfile.py +++ b/packages/google-cloud-recommender/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json index c22d64e4109a..3ccf1bb20a47 100644 --- a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json +++ b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommender", - "version": "2.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json index 26e1aa11fbee..01d4bcaa2c08 100644 --- a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json +++ b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommender", - "version": "2.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1/test_recommender.py b/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1/test_recommender.py index 982c9ede4b09..3e97bb052d1d 100644 --- a/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1/test_recommender.py +++ b/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1/test_recommender.py @@ -74,6 +74,13 @@ from google.cloud.recommender_v1.types import recommender_config from google.cloud.recommender_v1.types import recommender_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -313,6 +320,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RecommenderClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RecommenderClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -9627,10 +9677,13 @@ def test_list_insights_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_insights" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_insights_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_insights" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListInsightsRequest.pb( recommender_service.ListInsightsRequest() ) @@ -9656,6 +9709,10 @@ def test_list_insights_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListInsightsResponse() + post_with_metadata.return_value = ( + recommender_service.ListInsightsResponse(), + metadata, + ) client.list_insights( request, @@ -9667,6 +9724,7 @@ def test_list_insights_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_insight_rest_bad_request( @@ -9767,10 +9825,13 @@ def test_get_insight_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_insight" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_get_insight_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_insight" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetInsightRequest.pb( recommender_service.GetInsightRequest() ) @@ -9794,6 +9855,7 @@ def test_get_insight_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight.Insight() + post_with_metadata.return_value = insight.Insight(), metadata client.get_insight( request, @@ -9805,6 +9867,7 @@ def test_get_insight_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_insight_accepted_rest_bad_request( @@ -9905,10 +9968,14 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_insight_accepted" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_insight_accepted_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_insight_accepted" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkInsightAcceptedRequest.pb( recommender_service.MarkInsightAcceptedRequest() ) @@ -9932,6 +9999,7 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight.Insight() + post_with_metadata.return_value = insight.Insight(), metadata client.mark_insight_accepted( request, @@ -9943,6 +10011,7 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_recommendations_rest_bad_request( @@ -10027,10 +10096,13 @@ def test_list_recommendations_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_recommendations" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_recommendations_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_recommendations" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListRecommendationsRequest.pb( recommender_service.ListRecommendationsRequest() ) @@ -10056,6 +10128,10 @@ def test_list_recommendations_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListRecommendationsResponse() + post_with_metadata.return_value = ( + recommender_service.ListRecommendationsResponse(), + metadata, + ) client.list_recommendations( request, @@ -10067,6 +10143,7 @@ def test_list_recommendations_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_recommendation_rest_bad_request( @@ -10165,10 +10242,13 @@ def test_get_recommendation_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_recommendation" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_get_recommendation_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_recommendation" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetRecommendationRequest.pb( recommender_service.GetRecommendationRequest() ) @@ -10194,6 +10274,7 @@ def test_get_recommendation_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.get_recommendation( request, @@ -10205,6 +10286,7 @@ def test_get_recommendation_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_dismissed_rest_bad_request( @@ -10303,10 +10385,14 @@ def test_mark_recommendation_dismissed_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_dismissed" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_dismissed_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_dismissed" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationDismissedRequest.pb( recommender_service.MarkRecommendationDismissedRequest() ) @@ -10332,6 +10418,7 @@ def test_mark_recommendation_dismissed_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_dismissed( request, @@ -10343,6 +10430,7 @@ def test_mark_recommendation_dismissed_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_claimed_rest_bad_request( @@ -10441,10 +10529,14 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_claimed" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_claimed_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_claimed" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationClaimedRequest.pb( recommender_service.MarkRecommendationClaimedRequest() ) @@ -10470,6 +10562,7 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_claimed( request, @@ -10481,6 +10574,7 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_succeeded_rest_bad_request( @@ -10579,10 +10673,14 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_succeeded" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_succeeded_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_succeeded" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationSucceededRequest.pb( recommender_service.MarkRecommendationSucceededRequest() ) @@ -10608,6 +10706,7 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_succeeded( request, @@ -10619,6 +10718,7 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_failed_rest_bad_request( @@ -10717,10 +10817,14 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_failed" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_failed_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_failed" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationFailedRequest.pb( recommender_service.MarkRecommendationFailedRequest() ) @@ -10746,6 +10850,7 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_failed( request, @@ -10757,6 +10862,7 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_recommender_config_rest_bad_request( @@ -10851,10 +10957,14 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_recommender_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_get_recommender_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_recommender_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetRecommenderConfigRequest.pb( recommender_service.GetRecommenderConfigRequest() ) @@ -10880,6 +10990,10 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_config.RecommenderConfig() + post_with_metadata.return_value = ( + recommender_config.RecommenderConfig(), + metadata, + ) client.get_recommender_config( request, @@ -10891,6 +11005,7 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_recommender_config_rest_bad_request( @@ -11067,10 +11182,14 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_update_recommender_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_update_recommender_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_update_recommender_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.UpdateRecommenderConfigRequest.pb( recommender_service.UpdateRecommenderConfigRequest() ) @@ -11096,6 +11215,10 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_recommender_config.RecommenderConfig() + post_with_metadata.return_value = ( + gcr_recommender_config.RecommenderConfig(), + metadata, + ) client.update_recommender_config( request, @@ -11107,6 +11230,7 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_insight_type_config_rest_bad_request( @@ -11201,10 +11325,14 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_insight_type_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_get_insight_type_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_insight_type_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetInsightTypeConfigRequest.pb( recommender_service.GetInsightTypeConfigRequest() ) @@ -11230,6 +11358,10 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight_type_config.InsightTypeConfig() + post_with_metadata.return_value = ( + insight_type_config.InsightTypeConfig(), + metadata, + ) client.get_insight_type_config( request, @@ -11241,6 +11373,7 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_insight_type_config_rest_bad_request( @@ -11417,10 +11550,14 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_update_insight_type_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_update_insight_type_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_update_insight_type_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.UpdateInsightTypeConfigRequest.pb( recommender_service.UpdateInsightTypeConfigRequest() ) @@ -11446,6 +11583,10 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_insight_type_config.InsightTypeConfig() + post_with_metadata.return_value = ( + gcr_insight_type_config.InsightTypeConfig(), + metadata, + ) client.update_insight_type_config( request, @@ -11457,6 +11598,7 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1beta1/test_recommender.py b/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1beta1/test_recommender.py index afac04746868..c6c757571702 100644 --- a/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1beta1/test_recommender.py +++ b/packages/google-cloud-recommender/tests/unit/gapic/recommender_v1beta1/test_recommender.py @@ -74,6 +74,13 @@ from google.cloud.recommender_v1beta1.types import recommender_config from google.cloud.recommender_v1beta1.types import recommender_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -313,6 +320,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = RecommenderClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = RecommenderClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -10249,10 +10299,13 @@ def test_list_insights_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_insights" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_insights_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_insights" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListInsightsRequest.pb( recommender_service.ListInsightsRequest() ) @@ -10278,6 +10331,10 @@ def test_list_insights_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListInsightsResponse() + post_with_metadata.return_value = ( + recommender_service.ListInsightsResponse(), + metadata, + ) client.list_insights( request, @@ -10289,6 +10346,7 @@ def test_list_insights_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_insight_rest_bad_request( @@ -10389,10 +10447,13 @@ def test_get_insight_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_insight" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_get_insight_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_insight" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetInsightRequest.pb( recommender_service.GetInsightRequest() ) @@ -10416,6 +10477,7 @@ def test_get_insight_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight.Insight() + post_with_metadata.return_value = insight.Insight(), metadata client.get_insight( request, @@ -10427,6 +10489,7 @@ def test_get_insight_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_insight_accepted_rest_bad_request( @@ -10527,10 +10590,14 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_insight_accepted" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_insight_accepted_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_insight_accepted" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkInsightAcceptedRequest.pb( recommender_service.MarkInsightAcceptedRequest() ) @@ -10554,6 +10621,7 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight.Insight() + post_with_metadata.return_value = insight.Insight(), metadata client.mark_insight_accepted( request, @@ -10565,6 +10633,7 @@ def test_mark_insight_accepted_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_recommendations_rest_bad_request( @@ -10649,10 +10718,13 @@ def test_list_recommendations_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_recommendations" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_recommendations_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_recommendations" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListRecommendationsRequest.pb( recommender_service.ListRecommendationsRequest() ) @@ -10678,6 +10750,10 @@ def test_list_recommendations_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListRecommendationsResponse() + post_with_metadata.return_value = ( + recommender_service.ListRecommendationsResponse(), + metadata, + ) client.list_recommendations( request, @@ -10689,6 +10765,7 @@ def test_list_recommendations_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_recommendation_rest_bad_request( @@ -10787,10 +10864,13 @@ def test_get_recommendation_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_recommendation" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_get_recommendation_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_recommendation" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetRecommendationRequest.pb( recommender_service.GetRecommendationRequest() ) @@ -10816,6 +10896,7 @@ def test_get_recommendation_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.get_recommendation( request, @@ -10827,6 +10908,7 @@ def test_get_recommendation_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_claimed_rest_bad_request( @@ -10925,10 +11007,14 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_claimed" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_claimed_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_claimed" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationClaimedRequest.pb( recommender_service.MarkRecommendationClaimedRequest() ) @@ -10954,6 +11040,7 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_claimed( request, @@ -10965,6 +11052,7 @@ def test_mark_recommendation_claimed_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_succeeded_rest_bad_request( @@ -11063,10 +11151,14 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_succeeded" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_succeeded_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_succeeded" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationSucceededRequest.pb( recommender_service.MarkRecommendationSucceededRequest() ) @@ -11092,6 +11184,7 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_succeeded( request, @@ -11103,6 +11196,7 @@ def test_mark_recommendation_succeeded_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_mark_recommendation_failed_rest_bad_request( @@ -11201,10 +11295,14 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_mark_recommendation_failed" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_mark_recommendation_failed_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_mark_recommendation_failed" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.MarkRecommendationFailedRequest.pb( recommender_service.MarkRecommendationFailedRequest() ) @@ -11230,6 +11328,7 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommendation.Recommendation() + post_with_metadata.return_value = recommendation.Recommendation(), metadata client.mark_recommendation_failed( request, @@ -11241,6 +11340,7 @@ def test_mark_recommendation_failed_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_recommender_config_rest_bad_request( @@ -11335,10 +11435,14 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_recommender_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_get_recommender_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_recommender_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetRecommenderConfigRequest.pb( recommender_service.GetRecommenderConfigRequest() ) @@ -11364,6 +11468,10 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_config.RecommenderConfig() + post_with_metadata.return_value = ( + recommender_config.RecommenderConfig(), + metadata, + ) client.get_recommender_config( request, @@ -11375,6 +11483,7 @@ def test_get_recommender_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_recommender_config_rest_bad_request( @@ -11551,10 +11660,14 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_update_recommender_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_update_recommender_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_update_recommender_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.UpdateRecommenderConfigRequest.pb( recommender_service.UpdateRecommenderConfigRequest() ) @@ -11580,6 +11693,10 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_recommender_config.RecommenderConfig() + post_with_metadata.return_value = ( + gcr_recommender_config.RecommenderConfig(), + metadata, + ) client.update_recommender_config( request, @@ -11591,6 +11708,7 @@ def test_update_recommender_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_insight_type_config_rest_bad_request( @@ -11685,10 +11803,14 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_get_insight_type_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_get_insight_type_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_get_insight_type_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.GetInsightTypeConfigRequest.pb( recommender_service.GetInsightTypeConfigRequest() ) @@ -11714,6 +11836,10 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = insight_type_config.InsightTypeConfig() + post_with_metadata.return_value = ( + insight_type_config.InsightTypeConfig(), + metadata, + ) client.get_insight_type_config( request, @@ -11725,6 +11851,7 @@ def test_get_insight_type_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_insight_type_config_rest_bad_request( @@ -11901,10 +12028,14 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_update_insight_type_config" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, + "post_update_insight_type_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_update_insight_type_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.UpdateInsightTypeConfigRequest.pb( recommender_service.UpdateInsightTypeConfigRequest() ) @@ -11930,6 +12061,10 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_insight_type_config.InsightTypeConfig() + post_with_metadata.return_value = ( + gcr_insight_type_config.InsightTypeConfig(), + metadata, + ) client.update_insight_type_config( request, @@ -11941,6 +12076,7 @@ def test_update_insight_type_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_recommenders_rest_bad_request( @@ -12025,10 +12161,13 @@ def test_list_recommenders_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_recommenders" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_recommenders_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_recommenders" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListRecommendersRequest.pb( recommender_service.ListRecommendersRequest() ) @@ -12054,6 +12193,10 @@ def test_list_recommenders_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListRecommendersResponse() + post_with_metadata.return_value = ( + recommender_service.ListRecommendersResponse(), + metadata, + ) client.list_recommenders( request, @@ -12065,6 +12208,7 @@ def test_list_recommenders_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_insight_types_rest_bad_request( @@ -12149,10 +12293,13 @@ def test_list_insight_types_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.RecommenderRestInterceptor, "post_list_insight_types" ) as post, mock.patch.object( + transports.RecommenderRestInterceptor, "post_list_insight_types_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.RecommenderRestInterceptor, "pre_list_insight_types" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = recommender_service.ListInsightTypesRequest.pb( recommender_service.ListInsightTypesRequest() ) @@ -12178,6 +12325,10 @@ def test_list_insight_types_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = recommender_service.ListInsightTypesResponse() + post_with_metadata.return_value = ( + recommender_service.ListInsightTypesResponse(), + metadata, + ) client.list_insight_types( request, @@ -12189,6 +12340,7 @@ def test_list_insight_types_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-redis-cluster/README.rst b/packages/google-cloud-redis-cluster/README.rst index 6e678741d5bf..8c3221d58a73 100644 --- a/packages/google-cloud-redis-cluster/README.rst +++ b/packages/google-cloud-redis-cluster/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Google Cloud Memorystore for Redis API.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Google Cloud Memorystore for Redis API.: https://cloud.google.com/redis/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py index 7daf9a1dd221..558c8aab67c5 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py index 7daf9a1dd221..558c8aab67c5 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/client.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/client.py index 9dc71f07cef8..003b20a68d59 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/client.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -694,6 +696,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2696,16 +2725,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2751,16 +2784,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -2917,16 +2954,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2972,16 +3013,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/transports/rest.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/transports/rest.py index e98457b52896..6784f5d023a9 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/transports/rest.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/services/cloud_redis_cluster/transports/rest.py @@ -208,12 +208,35 @@ def post_backup_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for backup_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_backup_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_backup_cluster` interceptor runs + before the `post_backup_cluster_with_metadata` interceptor. """ return response + def post_backup_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for backup_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_backup_cluster_with_metadata` + interceptor in new development instead of the `post_backup_cluster` interceptor. + When both interceptors are used, this `post_backup_cluster_with_metadata` interceptor runs after the + `post_backup_cluster` interceptor. The (possibly modified) response returned by + `post_backup_cluster` will be passed to + `post_backup_cluster_with_metadata`. + """ + return response, metadata + def pre_create_cluster( self, request: cloud_redis_cluster.CreateClusterRequest, @@ -234,12 +257,35 @@ def post_create_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_create_cluster` interceptor runs + before the `post_create_cluster_with_metadata` interceptor. """ return response + def post_create_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_create_cluster_with_metadata` + interceptor in new development instead of the `post_create_cluster` interceptor. + When both interceptors are used, this `post_create_cluster_with_metadata` interceptor runs after the + `post_create_cluster` interceptor. The (possibly modified) response returned by + `post_create_cluster` will be passed to + `post_create_cluster_with_metadata`. + """ + return response, metadata + def pre_delete_backup( self, request: cloud_redis_cluster.DeleteBackupRequest, @@ -259,12 +305,35 @@ def post_delete_backup( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_delete_backup` interceptor runs + before the `post_delete_backup_with_metadata` interceptor. """ return response + def post_delete_backup_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_delete_backup_with_metadata` + interceptor in new development instead of the `post_delete_backup` interceptor. + When both interceptors are used, this `post_delete_backup_with_metadata` interceptor runs after the + `post_delete_backup` interceptor. The (possibly modified) response returned by + `post_delete_backup` will be passed to + `post_delete_backup_with_metadata`. + """ + return response, metadata + def pre_delete_cluster( self, request: cloud_redis_cluster.DeleteClusterRequest, @@ -285,12 +354,35 @@ def post_delete_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_delete_cluster` interceptor runs + before the `post_delete_cluster_with_metadata` interceptor. """ return response + def post_delete_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_delete_cluster_with_metadata` + interceptor in new development instead of the `post_delete_cluster` interceptor. + When both interceptors are used, this `post_delete_cluster_with_metadata` interceptor runs after the + `post_delete_cluster` interceptor. The (possibly modified) response returned by + `post_delete_cluster` will be passed to + `post_delete_cluster_with_metadata`. + """ + return response, metadata + def pre_export_backup( self, request: cloud_redis_cluster.ExportBackupRequest, @@ -310,12 +402,35 @@ def post_export_backup( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_export_backup` interceptor runs + before the `post_export_backup_with_metadata` interceptor. """ return response + def post_export_backup_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_export_backup_with_metadata` + interceptor in new development instead of the `post_export_backup` interceptor. + When both interceptors are used, this `post_export_backup_with_metadata` interceptor runs after the + `post_export_backup` interceptor. The (possibly modified) response returned by + `post_export_backup` will be passed to + `post_export_backup_with_metadata`. + """ + return response, metadata + def pre_get_backup( self, request: cloud_redis_cluster.GetBackupRequest, @@ -335,12 +450,35 @@ def post_get_backup( ) -> cloud_redis_cluster.Backup: """Post-rpc interceptor for get_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_backup` interceptor runs + before the `post_get_backup_with_metadata` interceptor. """ return response + def post_get_backup_with_metadata( + self, + response: cloud_redis_cluster.Backup, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis_cluster.Backup, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_backup_with_metadata` + interceptor in new development instead of the `post_get_backup` interceptor. + When both interceptors are used, this `post_get_backup_with_metadata` interceptor runs after the + `post_get_backup` interceptor. The (possibly modified) response returned by + `post_get_backup` will be passed to + `post_get_backup_with_metadata`. + """ + return response, metadata + def pre_get_backup_collection( self, request: cloud_redis_cluster.GetBackupCollectionRequest, @@ -361,12 +499,37 @@ def post_get_backup_collection( ) -> cloud_redis_cluster.BackupCollection: """Post-rpc interceptor for get_backup_collection - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_backup_collection_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_backup_collection` interceptor runs + before the `post_get_backup_collection_with_metadata` interceptor. """ return response + def post_get_backup_collection_with_metadata( + self, + response: cloud_redis_cluster.BackupCollection, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.BackupCollection, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_backup_collection + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_backup_collection_with_metadata` + interceptor in new development instead of the `post_get_backup_collection` interceptor. + When both interceptors are used, this `post_get_backup_collection_with_metadata` interceptor runs after the + `post_get_backup_collection` interceptor. The (possibly modified) response returned by + `post_get_backup_collection` will be passed to + `post_get_backup_collection_with_metadata`. + """ + return response, metadata + def pre_get_cluster( self, request: cloud_redis_cluster.GetClusterRequest, @@ -386,12 +549,35 @@ def post_get_cluster( ) -> cloud_redis_cluster.Cluster: """Post-rpc interceptor for get_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_cluster` interceptor runs + before the `post_get_cluster_with_metadata` interceptor. """ return response + def post_get_cluster_with_metadata( + self, + response: cloud_redis_cluster.Cluster, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis_cluster.Cluster, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_cluster_with_metadata` + interceptor in new development instead of the `post_get_cluster` interceptor. + When both interceptors are used, this `post_get_cluster_with_metadata` interceptor runs after the + `post_get_cluster` interceptor. The (possibly modified) response returned by + `post_get_cluster` will be passed to + `post_get_cluster_with_metadata`. + """ + return response, metadata + def pre_get_cluster_certificate_authority( self, request: cloud_redis_cluster.GetClusterCertificateAuthorityRequest, @@ -412,12 +598,38 @@ def post_get_cluster_certificate_authority( ) -> cloud_redis_cluster.CertificateAuthority: """Post-rpc interceptor for get_cluster_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_cluster_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_cluster_certificate_authority` interceptor runs + before the `post_get_cluster_certificate_authority_with_metadata` interceptor. """ return response + def post_get_cluster_certificate_authority_with_metadata( + self, + response: cloud_redis_cluster.CertificateAuthority, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.CertificateAuthority, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_cluster_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_cluster_certificate_authority_with_metadata` + interceptor in new development instead of the `post_get_cluster_certificate_authority` interceptor. + When both interceptors are used, this `post_get_cluster_certificate_authority_with_metadata` interceptor runs after the + `post_get_cluster_certificate_authority` interceptor. The (possibly modified) response returned by + `post_get_cluster_certificate_authority` will be passed to + `post_get_cluster_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_list_backup_collections( self, request: cloud_redis_cluster.ListBackupCollectionsRequest, @@ -438,12 +650,38 @@ def post_list_backup_collections( ) -> cloud_redis_cluster.ListBackupCollectionsResponse: """Post-rpc interceptor for list_backup_collections - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_backup_collections_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_backup_collections` interceptor runs + before the `post_list_backup_collections_with_metadata` interceptor. """ return response + def post_list_backup_collections_with_metadata( + self, + response: cloud_redis_cluster.ListBackupCollectionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListBackupCollectionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_backup_collections + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_backup_collections_with_metadata` + interceptor in new development instead of the `post_list_backup_collections` interceptor. + When both interceptors are used, this `post_list_backup_collections_with_metadata` interceptor runs after the + `post_list_backup_collections` interceptor. The (possibly modified) response returned by + `post_list_backup_collections` will be passed to + `post_list_backup_collections_with_metadata`. + """ + return response, metadata + def pre_list_backups( self, request: cloud_redis_cluster.ListBackupsRequest, @@ -463,12 +701,37 @@ def post_list_backups( ) -> cloud_redis_cluster.ListBackupsResponse: """Post-rpc interceptor for list_backups - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_backups_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_backups` interceptor runs + before the `post_list_backups_with_metadata` interceptor. """ return response + def post_list_backups_with_metadata( + self, + response: cloud_redis_cluster.ListBackupsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListBackupsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_backups + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_backups_with_metadata` + interceptor in new development instead of the `post_list_backups` interceptor. + When both interceptors are used, this `post_list_backups_with_metadata` interceptor runs after the + `post_list_backups` interceptor. The (possibly modified) response returned by + `post_list_backups` will be passed to + `post_list_backups_with_metadata`. + """ + return response, metadata + def pre_list_clusters( self, request: cloud_redis_cluster.ListClustersRequest, @@ -488,12 +751,38 @@ def post_list_clusters( ) -> cloud_redis_cluster.ListClustersResponse: """Post-rpc interceptor for list_clusters - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_clusters_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_clusters` interceptor runs + before the `post_list_clusters_with_metadata` interceptor. """ return response + def post_list_clusters_with_metadata( + self, + response: cloud_redis_cluster.ListClustersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListClustersResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_clusters + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_clusters_with_metadata` + interceptor in new development instead of the `post_list_clusters` interceptor. + When both interceptors are used, this `post_list_clusters_with_metadata` interceptor runs after the + `post_list_clusters` interceptor. The (possibly modified) response returned by + `post_list_clusters` will be passed to + `post_list_clusters_with_metadata`. + """ + return response, metadata + def pre_reschedule_cluster_maintenance( self, request: cloud_redis_cluster.RescheduleClusterMaintenanceRequest, @@ -514,12 +803,35 @@ def post_reschedule_cluster_maintenance( ) -> operations_pb2.Operation: """Post-rpc interceptor for reschedule_cluster_maintenance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_reschedule_cluster_maintenance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_reschedule_cluster_maintenance` interceptor runs + before the `post_reschedule_cluster_maintenance_with_metadata` interceptor. """ return response + def post_reschedule_cluster_maintenance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for reschedule_cluster_maintenance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_reschedule_cluster_maintenance_with_metadata` + interceptor in new development instead of the `post_reschedule_cluster_maintenance` interceptor. + When both interceptors are used, this `post_reschedule_cluster_maintenance_with_metadata` interceptor runs after the + `post_reschedule_cluster_maintenance` interceptor. The (possibly modified) response returned by + `post_reschedule_cluster_maintenance` will be passed to + `post_reschedule_cluster_maintenance_with_metadata`. + """ + return response, metadata + def pre_update_cluster( self, request: cloud_redis_cluster.UpdateClusterRequest, @@ -540,12 +852,35 @@ def post_update_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_update_cluster` interceptor runs + before the `post_update_cluster_with_metadata` interceptor. """ return response + def post_update_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_update_cluster_with_metadata` + interceptor in new development instead of the `post_update_cluster` interceptor. + When both interceptors are used, this `post_update_cluster_with_metadata` interceptor runs after the + `post_update_cluster` interceptor. The (possibly modified) response returned by + `post_update_cluster` will be passed to + `post_update_cluster_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -976,6 +1311,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_backup_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_backup_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1124,6 +1463,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1265,6 +1608,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1407,6 +1754,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1554,6 +1905,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1694,6 +2049,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1839,6 +2198,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_backup_collection(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_backup_collection_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1981,6 +2344,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2126,6 +2493,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_cluster_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_cluster_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2273,6 +2647,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_backup_collections(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_backup_collections_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2417,6 +2795,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_backups(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_backups_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2559,6 +2941,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_clusters(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_clusters_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2713,6 +3099,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_reschedule_cluster_maintenance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_reschedule_cluster_maintenance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2861,6 +3254,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py index 7daf9a1dd221..558c8aab67c5 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.13" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/client.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/client.py index afe3f478c541..60fc465441ff 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/client.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -694,6 +696,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2696,16 +2725,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2751,16 +2784,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -2917,16 +2954,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2972,16 +3013,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/transports/rest.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/transports/rest.py index e9e7ad965f6b..17b473607c6e 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/transports/rest.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/services/cloud_redis_cluster/transports/rest.py @@ -208,12 +208,35 @@ def post_backup_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for backup_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_backup_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_backup_cluster` interceptor runs + before the `post_backup_cluster_with_metadata` interceptor. """ return response + def post_backup_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for backup_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_backup_cluster_with_metadata` + interceptor in new development instead of the `post_backup_cluster` interceptor. + When both interceptors are used, this `post_backup_cluster_with_metadata` interceptor runs after the + `post_backup_cluster` interceptor. The (possibly modified) response returned by + `post_backup_cluster` will be passed to + `post_backup_cluster_with_metadata`. + """ + return response, metadata + def pre_create_cluster( self, request: cloud_redis_cluster.CreateClusterRequest, @@ -234,12 +257,35 @@ def post_create_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_create_cluster` interceptor runs + before the `post_create_cluster_with_metadata` interceptor. """ return response + def post_create_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_create_cluster_with_metadata` + interceptor in new development instead of the `post_create_cluster` interceptor. + When both interceptors are used, this `post_create_cluster_with_metadata` interceptor runs after the + `post_create_cluster` interceptor. The (possibly modified) response returned by + `post_create_cluster` will be passed to + `post_create_cluster_with_metadata`. + """ + return response, metadata + def pre_delete_backup( self, request: cloud_redis_cluster.DeleteBackupRequest, @@ -259,12 +305,35 @@ def post_delete_backup( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_delete_backup` interceptor runs + before the `post_delete_backup_with_metadata` interceptor. """ return response + def post_delete_backup_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_delete_backup_with_metadata` + interceptor in new development instead of the `post_delete_backup` interceptor. + When both interceptors are used, this `post_delete_backup_with_metadata` interceptor runs after the + `post_delete_backup` interceptor. The (possibly modified) response returned by + `post_delete_backup` will be passed to + `post_delete_backup_with_metadata`. + """ + return response, metadata + def pre_delete_cluster( self, request: cloud_redis_cluster.DeleteClusterRequest, @@ -285,12 +354,35 @@ def post_delete_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_delete_cluster` interceptor runs + before the `post_delete_cluster_with_metadata` interceptor. """ return response + def post_delete_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_delete_cluster_with_metadata` + interceptor in new development instead of the `post_delete_cluster` interceptor. + When both interceptors are used, this `post_delete_cluster_with_metadata` interceptor runs after the + `post_delete_cluster` interceptor. The (possibly modified) response returned by + `post_delete_cluster` will be passed to + `post_delete_cluster_with_metadata`. + """ + return response, metadata + def pre_export_backup( self, request: cloud_redis_cluster.ExportBackupRequest, @@ -310,12 +402,35 @@ def post_export_backup( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_export_backup` interceptor runs + before the `post_export_backup_with_metadata` interceptor. """ return response + def post_export_backup_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_export_backup_with_metadata` + interceptor in new development instead of the `post_export_backup` interceptor. + When both interceptors are used, this `post_export_backup_with_metadata` interceptor runs after the + `post_export_backup` interceptor. The (possibly modified) response returned by + `post_export_backup` will be passed to + `post_export_backup_with_metadata`. + """ + return response, metadata + def pre_get_backup( self, request: cloud_redis_cluster.GetBackupRequest, @@ -335,12 +450,35 @@ def post_get_backup( ) -> cloud_redis_cluster.Backup: """Post-rpc interceptor for get_backup - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_backup_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_backup` interceptor runs + before the `post_get_backup_with_metadata` interceptor. """ return response + def post_get_backup_with_metadata( + self, + response: cloud_redis_cluster.Backup, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis_cluster.Backup, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_backup + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_backup_with_metadata` + interceptor in new development instead of the `post_get_backup` interceptor. + When both interceptors are used, this `post_get_backup_with_metadata` interceptor runs after the + `post_get_backup` interceptor. The (possibly modified) response returned by + `post_get_backup` will be passed to + `post_get_backup_with_metadata`. + """ + return response, metadata + def pre_get_backup_collection( self, request: cloud_redis_cluster.GetBackupCollectionRequest, @@ -361,12 +499,37 @@ def post_get_backup_collection( ) -> cloud_redis_cluster.BackupCollection: """Post-rpc interceptor for get_backup_collection - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_backup_collection_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_backup_collection` interceptor runs + before the `post_get_backup_collection_with_metadata` interceptor. """ return response + def post_get_backup_collection_with_metadata( + self, + response: cloud_redis_cluster.BackupCollection, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.BackupCollection, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for get_backup_collection + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_backup_collection_with_metadata` + interceptor in new development instead of the `post_get_backup_collection` interceptor. + When both interceptors are used, this `post_get_backup_collection_with_metadata` interceptor runs after the + `post_get_backup_collection` interceptor. The (possibly modified) response returned by + `post_get_backup_collection` will be passed to + `post_get_backup_collection_with_metadata`. + """ + return response, metadata + def pre_get_cluster( self, request: cloud_redis_cluster.GetClusterRequest, @@ -386,12 +549,35 @@ def post_get_cluster( ) -> cloud_redis_cluster.Cluster: """Post-rpc interceptor for get_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_cluster` interceptor runs + before the `post_get_cluster_with_metadata` interceptor. """ return response + def post_get_cluster_with_metadata( + self, + response: cloud_redis_cluster.Cluster, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis_cluster.Cluster, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_cluster_with_metadata` + interceptor in new development instead of the `post_get_cluster` interceptor. + When both interceptors are used, this `post_get_cluster_with_metadata` interceptor runs after the + `post_get_cluster` interceptor. The (possibly modified) response returned by + `post_get_cluster` will be passed to + `post_get_cluster_with_metadata`. + """ + return response, metadata + def pre_get_cluster_certificate_authority( self, request: cloud_redis_cluster.GetClusterCertificateAuthorityRequest, @@ -412,12 +598,38 @@ def post_get_cluster_certificate_authority( ) -> cloud_redis_cluster.CertificateAuthority: """Post-rpc interceptor for get_cluster_certificate_authority - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_cluster_certificate_authority_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_get_cluster_certificate_authority` interceptor runs + before the `post_get_cluster_certificate_authority_with_metadata` interceptor. """ return response + def post_get_cluster_certificate_authority_with_metadata( + self, + response: cloud_redis_cluster.CertificateAuthority, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.CertificateAuthority, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_cluster_certificate_authority + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_get_cluster_certificate_authority_with_metadata` + interceptor in new development instead of the `post_get_cluster_certificate_authority` interceptor. + When both interceptors are used, this `post_get_cluster_certificate_authority_with_metadata` interceptor runs after the + `post_get_cluster_certificate_authority` interceptor. The (possibly modified) response returned by + `post_get_cluster_certificate_authority` will be passed to + `post_get_cluster_certificate_authority_with_metadata`. + """ + return response, metadata + def pre_list_backup_collections( self, request: cloud_redis_cluster.ListBackupCollectionsRequest, @@ -438,12 +650,38 @@ def post_list_backup_collections( ) -> cloud_redis_cluster.ListBackupCollectionsResponse: """Post-rpc interceptor for list_backup_collections - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_backup_collections_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_backup_collections` interceptor runs + before the `post_list_backup_collections_with_metadata` interceptor. """ return response + def post_list_backup_collections_with_metadata( + self, + response: cloud_redis_cluster.ListBackupCollectionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListBackupCollectionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_backup_collections + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_backup_collections_with_metadata` + interceptor in new development instead of the `post_list_backup_collections` interceptor. + When both interceptors are used, this `post_list_backup_collections_with_metadata` interceptor runs after the + `post_list_backup_collections` interceptor. The (possibly modified) response returned by + `post_list_backup_collections` will be passed to + `post_list_backup_collections_with_metadata`. + """ + return response, metadata + def pre_list_backups( self, request: cloud_redis_cluster.ListBackupsRequest, @@ -463,12 +701,37 @@ def post_list_backups( ) -> cloud_redis_cluster.ListBackupsResponse: """Post-rpc interceptor for list_backups - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_backups_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_backups` interceptor runs + before the `post_list_backups_with_metadata` interceptor. """ return response + def post_list_backups_with_metadata( + self, + response: cloud_redis_cluster.ListBackupsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListBackupsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_backups + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_backups_with_metadata` + interceptor in new development instead of the `post_list_backups` interceptor. + When both interceptors are used, this `post_list_backups_with_metadata` interceptor runs after the + `post_list_backups` interceptor. The (possibly modified) response returned by + `post_list_backups` will be passed to + `post_list_backups_with_metadata`. + """ + return response, metadata + def pre_list_clusters( self, request: cloud_redis_cluster.ListClustersRequest, @@ -488,12 +751,38 @@ def post_list_clusters( ) -> cloud_redis_cluster.ListClustersResponse: """Post-rpc interceptor for list_clusters - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_clusters_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_list_clusters` interceptor runs + before the `post_list_clusters_with_metadata` interceptor. """ return response + def post_list_clusters_with_metadata( + self, + response: cloud_redis_cluster.ListClustersResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis_cluster.ListClustersResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_clusters + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_list_clusters_with_metadata` + interceptor in new development instead of the `post_list_clusters` interceptor. + When both interceptors are used, this `post_list_clusters_with_metadata` interceptor runs after the + `post_list_clusters` interceptor. The (possibly modified) response returned by + `post_list_clusters` will be passed to + `post_list_clusters_with_metadata`. + """ + return response, metadata + def pre_reschedule_cluster_maintenance( self, request: cloud_redis_cluster.RescheduleClusterMaintenanceRequest, @@ -514,12 +803,35 @@ def post_reschedule_cluster_maintenance( ) -> operations_pb2.Operation: """Post-rpc interceptor for reschedule_cluster_maintenance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_reschedule_cluster_maintenance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_reschedule_cluster_maintenance` interceptor runs + before the `post_reschedule_cluster_maintenance_with_metadata` interceptor. """ return response + def post_reschedule_cluster_maintenance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for reschedule_cluster_maintenance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_reschedule_cluster_maintenance_with_metadata` + interceptor in new development instead of the `post_reschedule_cluster_maintenance` interceptor. + When both interceptors are used, this `post_reschedule_cluster_maintenance_with_metadata` interceptor runs after the + `post_reschedule_cluster_maintenance` interceptor. The (possibly modified) response returned by + `post_reschedule_cluster_maintenance` will be passed to + `post_reschedule_cluster_maintenance_with_metadata`. + """ + return response, metadata + def pre_update_cluster( self, request: cloud_redis_cluster.UpdateClusterRequest, @@ -540,12 +852,35 @@ def post_update_cluster( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_cluster - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_cluster_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedisCluster server but before - it is returned to user code. + it is returned to user code. This `post_update_cluster` interceptor runs + before the `post_update_cluster_with_metadata` interceptor. """ return response + def post_update_cluster_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_cluster + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedisCluster server but before it is returned to user code. + + We recommend only using this `post_update_cluster_with_metadata` + interceptor in new development instead of the `post_update_cluster` interceptor. + When both interceptors are used, this `post_update_cluster_with_metadata` interceptor runs after the + `post_update_cluster` interceptor. The (possibly modified) response returned by + `post_update_cluster` will be passed to + `post_update_cluster_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -976,6 +1311,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_backup_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_backup_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1124,6 +1463,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1265,6 +1608,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1407,6 +1754,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1554,6 +1905,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1694,6 +2049,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_backup(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_backup_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1839,6 +2198,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_backup_collection(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_backup_collection_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1981,6 +2344,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2126,6 +2493,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_cluster_certificate_authority(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_cluster_certificate_authority_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2273,6 +2647,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_backup_collections(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_backup_collections_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2417,6 +2795,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_backups(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_backups_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2559,6 +2941,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_clusters(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_clusters_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2713,6 +3099,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_reschedule_cluster_maintenance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_reschedule_cluster_maintenance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2861,6 +3254,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_cluster(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_cluster_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-redis-cluster/noxfile.py b/packages/google-cloud-redis-cluster/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-redis-cluster/noxfile.py +++ b/packages/google-cloud-redis-cluster/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json index df9b9ad76506..9713cf9d56ac 100644 --- a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json +++ b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis-cluster", - "version": "0.1.13" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json index 5da4bd7ce2e5..3512a9cf90ac 100644 --- a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json +++ b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis-cluster", - "version": "0.1.13" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1/test_cloud_redis_cluster.py b/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1/test_cloud_redis_cluster.py index 67b419f25dff..d9f0636e0059 100644 --- a/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1/test_cloud_redis_cluster.py +++ b/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1/test_cloud_redis_cluster.py @@ -78,6 +78,13 @@ ) from google.cloud.redis_cluster_v1.types import cloud_redis_cluster +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -345,6 +352,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudRedisClusterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudRedisClusterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -10209,10 +10259,13 @@ def test_list_clusters_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_clusters" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_list_clusters_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_clusters" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListClustersRequest.pb( cloud_redis_cluster.ListClustersRequest() ) @@ -10238,6 +10291,10 @@ def test_list_clusters_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListClustersResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListClustersResponse(), + metadata, + ) client.list_clusters( request, @@ -10249,6 +10306,7 @@ def test_list_clusters_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_cluster_rest_bad_request( @@ -10363,10 +10421,13 @@ def test_get_cluster_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_get_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetClusterRequest.pb( cloud_redis_cluster.GetClusterRequest() ) @@ -10392,6 +10453,7 @@ def test_get_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.Cluster() + post_with_metadata.return_value = cloud_redis_cluster.Cluster(), metadata client.get_cluster( request, @@ -10403,6 +10465,7 @@ def test_get_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_cluster_rest_bad_request( @@ -10654,10 +10717,13 @@ def test_update_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_update_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_update_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_update_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.UpdateClusterRequest.pb( cloud_redis_cluster.UpdateClusterRequest() ) @@ -10681,6 +10747,7 @@ def test_update_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_cluster( request, @@ -10692,6 +10759,7 @@ def test_update_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_cluster_rest_bad_request( @@ -10772,10 +10840,13 @@ def test_delete_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_delete_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_delete_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_delete_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.DeleteClusterRequest.pb( cloud_redis_cluster.DeleteClusterRequest() ) @@ -10799,6 +10870,7 @@ def test_delete_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_cluster( request, @@ -10810,6 +10882,7 @@ def test_delete_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_cluster_rest_bad_request( @@ -11057,10 +11130,13 @@ def test_create_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_create_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_create_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_create_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.CreateClusterRequest.pb( cloud_redis_cluster.CreateClusterRequest() ) @@ -11084,6 +11160,7 @@ def test_create_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_cluster( request, @@ -11095,6 +11172,7 @@ def test_create_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_cluster_certificate_authority_rest_bad_request( @@ -11184,11 +11262,15 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): transports.CloudRedisClusterRestInterceptor, "post_get_cluster_certificate_authority", ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_get_cluster_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_cluster_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetClusterCertificateAuthorityRequest.pb( cloud_redis_cluster.GetClusterCertificateAuthorityRequest() ) @@ -11214,6 +11296,10 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.CertificateAuthority() + post_with_metadata.return_value = ( + cloud_redis_cluster.CertificateAuthority(), + metadata, + ) client.get_cluster_certificate_authority( request, @@ -11225,6 +11311,7 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_reschedule_cluster_maintenance_rest_bad_request( @@ -11306,11 +11393,15 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): transports.CloudRedisClusterRestInterceptor, "post_reschedule_cluster_maintenance", ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_reschedule_cluster_maintenance_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_reschedule_cluster_maintenance", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.RescheduleClusterMaintenanceRequest.pb( cloud_redis_cluster.RescheduleClusterMaintenanceRequest() ) @@ -11334,6 +11425,7 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.reschedule_cluster_maintenance( request, @@ -11345,6 +11437,7 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_backup_collections_rest_bad_request( @@ -11433,10 +11526,14 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_backup_collections" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_list_backup_collections_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_backup_collections" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListBackupCollectionsRequest.pb( cloud_redis_cluster.ListBackupCollectionsRequest() ) @@ -11462,6 +11559,10 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListBackupCollectionsResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListBackupCollectionsResponse(), + metadata, + ) client.list_backup_collections( request, @@ -11473,6 +11574,7 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_backup_collection_rest_bad_request( @@ -11569,10 +11671,14 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_backup_collection" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_get_backup_collection_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_backup_collection" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetBackupCollectionRequest.pb( cloud_redis_cluster.GetBackupCollectionRequest() ) @@ -11598,6 +11704,10 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.BackupCollection() + post_with_metadata.return_value = ( + cloud_redis_cluster.BackupCollection(), + metadata, + ) client.get_backup_collection( request, @@ -11609,6 +11719,7 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_backups_rest_bad_request( @@ -11699,10 +11810,13 @@ def test_list_backups_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_backups" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_list_backups_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_backups" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListBackupsRequest.pb( cloud_redis_cluster.ListBackupsRequest() ) @@ -11728,6 +11842,10 @@ def test_list_backups_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListBackupsResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListBackupsResponse(), + metadata, + ) client.list_backups( request, @@ -11739,6 +11857,7 @@ def test_list_backups_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_backup_rest_bad_request(request_type=cloud_redis_cluster.GetBackupRequest): @@ -11845,10 +11964,13 @@ def test_get_backup_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_get_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetBackupRequest.pb( cloud_redis_cluster.GetBackupRequest() ) @@ -11872,6 +11994,7 @@ def test_get_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.Backup() + post_with_metadata.return_value = cloud_redis_cluster.Backup(), metadata client.get_backup( request, @@ -11883,6 +12006,7 @@ def test_get_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_backup_rest_bad_request( @@ -11967,10 +12091,13 @@ def test_delete_backup_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_delete_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_delete_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_delete_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.DeleteBackupRequest.pb( cloud_redis_cluster.DeleteBackupRequest() ) @@ -11994,6 +12121,7 @@ def test_delete_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_backup( request, @@ -12005,6 +12133,7 @@ def test_delete_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_backup_rest_bad_request( @@ -12089,10 +12218,13 @@ def test_export_backup_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_export_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_export_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_export_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ExportBackupRequest.pb( cloud_redis_cluster.ExportBackupRequest() ) @@ -12116,6 +12248,7 @@ def test_export_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_backup( request, @@ -12127,6 +12260,7 @@ def test_export_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_backup_cluster_rest_bad_request( @@ -12207,10 +12341,13 @@ def test_backup_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_backup_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_backup_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_backup_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.BackupClusterRequest.pb( cloud_redis_cluster.BackupClusterRequest() ) @@ -12234,6 +12371,7 @@ def test_backup_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.backup_cluster( request, @@ -12245,6 +12383,7 @@ def test_backup_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1beta1/test_cloud_redis_cluster.py b/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1beta1/test_cloud_redis_cluster.py index 0a3cc8a2b17c..986ca68b1d54 100644 --- a/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1beta1/test_cloud_redis_cluster.py +++ b/packages/google-cloud-redis-cluster/tests/unit/gapic/redis_cluster_v1beta1/test_cloud_redis_cluster.py @@ -78,6 +78,13 @@ ) from google.cloud.redis_cluster_v1beta1.types import cloud_redis_cluster +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -345,6 +352,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudRedisClusterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudRedisClusterClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -10213,10 +10263,13 @@ def test_list_clusters_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_clusters" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_list_clusters_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_clusters" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListClustersRequest.pb( cloud_redis_cluster.ListClustersRequest() ) @@ -10242,6 +10295,10 @@ def test_list_clusters_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListClustersResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListClustersResponse(), + metadata, + ) client.list_clusters( request, @@ -10253,6 +10310,7 @@ def test_list_clusters_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_cluster_rest_bad_request( @@ -10367,10 +10425,13 @@ def test_get_cluster_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_get_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetClusterRequest.pb( cloud_redis_cluster.GetClusterRequest() ) @@ -10396,6 +10457,7 @@ def test_get_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.Cluster() + post_with_metadata.return_value = cloud_redis_cluster.Cluster(), metadata client.get_cluster( request, @@ -10407,6 +10469,7 @@ def test_get_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_cluster_rest_bad_request( @@ -10658,10 +10721,13 @@ def test_update_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_update_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_update_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_update_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.UpdateClusterRequest.pb( cloud_redis_cluster.UpdateClusterRequest() ) @@ -10685,6 +10751,7 @@ def test_update_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_cluster( request, @@ -10696,6 +10763,7 @@ def test_update_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_cluster_rest_bad_request( @@ -10776,10 +10844,13 @@ def test_delete_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_delete_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_delete_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_delete_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.DeleteClusterRequest.pb( cloud_redis_cluster.DeleteClusterRequest() ) @@ -10803,6 +10874,7 @@ def test_delete_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_cluster( request, @@ -10814,6 +10886,7 @@ def test_delete_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_cluster_rest_bad_request( @@ -11061,10 +11134,13 @@ def test_create_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_create_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_create_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_create_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.CreateClusterRequest.pb( cloud_redis_cluster.CreateClusterRequest() ) @@ -11088,6 +11164,7 @@ def test_create_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_cluster( request, @@ -11099,6 +11176,7 @@ def test_create_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_cluster_certificate_authority_rest_bad_request( @@ -11188,11 +11266,15 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): transports.CloudRedisClusterRestInterceptor, "post_get_cluster_certificate_authority", ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_get_cluster_certificate_authority_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_cluster_certificate_authority", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetClusterCertificateAuthorityRequest.pb( cloud_redis_cluster.GetClusterCertificateAuthorityRequest() ) @@ -11218,6 +11300,10 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.CertificateAuthority() + post_with_metadata.return_value = ( + cloud_redis_cluster.CertificateAuthority(), + metadata, + ) client.get_cluster_certificate_authority( request, @@ -11229,6 +11315,7 @@ def test_get_cluster_certificate_authority_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_reschedule_cluster_maintenance_rest_bad_request( @@ -11310,11 +11397,15 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): transports.CloudRedisClusterRestInterceptor, "post_reschedule_cluster_maintenance", ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_reschedule_cluster_maintenance_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_reschedule_cluster_maintenance", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.RescheduleClusterMaintenanceRequest.pb( cloud_redis_cluster.RescheduleClusterMaintenanceRequest() ) @@ -11338,6 +11429,7 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.reschedule_cluster_maintenance( request, @@ -11349,6 +11441,7 @@ def test_reschedule_cluster_maintenance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_backup_collections_rest_bad_request( @@ -11437,10 +11530,14 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_backup_collections" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_list_backup_collections_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_backup_collections" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListBackupCollectionsRequest.pb( cloud_redis_cluster.ListBackupCollectionsRequest() ) @@ -11466,6 +11563,10 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListBackupCollectionsResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListBackupCollectionsResponse(), + metadata, + ) client.list_backup_collections( request, @@ -11477,6 +11578,7 @@ def test_list_backup_collections_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_backup_collection_rest_bad_request( @@ -11573,10 +11675,14 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_backup_collection" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, + "post_get_backup_collection_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_backup_collection" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetBackupCollectionRequest.pb( cloud_redis_cluster.GetBackupCollectionRequest() ) @@ -11602,6 +11708,10 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.BackupCollection() + post_with_metadata.return_value = ( + cloud_redis_cluster.BackupCollection(), + metadata, + ) client.get_backup_collection( request, @@ -11613,6 +11723,7 @@ def test_get_backup_collection_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_backups_rest_bad_request( @@ -11703,10 +11814,13 @@ def test_list_backups_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_list_backups" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_list_backups_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_list_backups" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ListBackupsRequest.pb( cloud_redis_cluster.ListBackupsRequest() ) @@ -11732,6 +11846,10 @@ def test_list_backups_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.ListBackupsResponse() + post_with_metadata.return_value = ( + cloud_redis_cluster.ListBackupsResponse(), + metadata, + ) client.list_backups( request, @@ -11743,6 +11861,7 @@ def test_list_backups_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_backup_rest_bad_request(request_type=cloud_redis_cluster.GetBackupRequest): @@ -11849,10 +11968,13 @@ def test_get_backup_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_get_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_get_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_get_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.GetBackupRequest.pb( cloud_redis_cluster.GetBackupRequest() ) @@ -11876,6 +11998,7 @@ def test_get_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis_cluster.Backup() + post_with_metadata.return_value = cloud_redis_cluster.Backup(), metadata client.get_backup( request, @@ -11887,6 +12010,7 @@ def test_get_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_backup_rest_bad_request( @@ -11971,10 +12095,13 @@ def test_delete_backup_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_delete_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_delete_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_delete_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.DeleteBackupRequest.pb( cloud_redis_cluster.DeleteBackupRequest() ) @@ -11998,6 +12125,7 @@ def test_delete_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_backup( request, @@ -12009,6 +12137,7 @@ def test_delete_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_backup_rest_bad_request( @@ -12093,10 +12222,13 @@ def test_export_backup_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_export_backup" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_export_backup_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_export_backup" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.ExportBackupRequest.pb( cloud_redis_cluster.ExportBackupRequest() ) @@ -12120,6 +12252,7 @@ def test_export_backup_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_backup( request, @@ -12131,6 +12264,7 @@ def test_export_backup_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_backup_cluster_rest_bad_request( @@ -12211,10 +12345,13 @@ def test_backup_cluster_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisClusterRestInterceptor, "post_backup_cluster" ) as post, mock.patch.object( + transports.CloudRedisClusterRestInterceptor, "post_backup_cluster_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisClusterRestInterceptor, "pre_backup_cluster" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis_cluster.BackupClusterRequest.pb( cloud_redis_cluster.BackupClusterRequest() ) @@ -12238,6 +12375,7 @@ def test_backup_cluster_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.backup_cluster( request, @@ -12249,6 +12387,7 @@ def test_backup_cluster_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-redis/README.rst b/packages/google-cloud-redis/README.rst index 5b8f66b80254..d014151e46fd 100644 --- a/packages/google-cloud-redis/README.rst +++ b/packages/google-cloud-redis/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Redis.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Redis.: https://cloud.google.com/memorystore/docs/redis/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-redis/google/cloud/redis/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-redis/google/cloud/redis/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/client.py b/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/client.py index 728d00e4a1e5..e7eba7a6f8db 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -511,6 +513,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2247,16 +2276,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2302,16 +2335,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def delete_operation( self, @@ -2468,16 +2505,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -2523,16 +2564,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/transports/rest.py b/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/transports/rest.py index 69c204dddbf3..0a9bf7d15b68 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/transports/rest.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1/services/cloud_redis/transports/rest.py @@ -183,12 +183,35 @@ def post_create_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_create_instance` interceptor runs + before the `post_create_instance_with_metadata` interceptor. """ return response + def post_create_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_create_instance_with_metadata` + interceptor in new development instead of the `post_create_instance` interceptor. + When both interceptors are used, this `post_create_instance_with_metadata` interceptor runs after the + `post_create_instance` interceptor. The (possibly modified) response returned by + `post_create_instance` will be passed to + `post_create_instance_with_metadata`. + """ + return response, metadata + def pre_delete_instance( self, request: cloud_redis.DeleteInstanceRequest, @@ -208,12 +231,35 @@ def post_delete_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_delete_instance` interceptor runs + before the `post_delete_instance_with_metadata` interceptor. """ return response + def post_delete_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_delete_instance_with_metadata` + interceptor in new development instead of the `post_delete_instance` interceptor. + When both interceptors are used, this `post_delete_instance_with_metadata` interceptor runs after the + `post_delete_instance` interceptor. The (possibly modified) response returned by + `post_delete_instance` will be passed to + `post_delete_instance_with_metadata`. + """ + return response, metadata + def pre_export_instance( self, request: cloud_redis.ExportInstanceRequest, @@ -233,12 +279,35 @@ def post_export_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_export_instance` interceptor runs + before the `post_export_instance_with_metadata` interceptor. """ return response + def post_export_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_export_instance_with_metadata` + interceptor in new development instead of the `post_export_instance` interceptor. + When both interceptors are used, this `post_export_instance_with_metadata` interceptor runs after the + `post_export_instance` interceptor. The (possibly modified) response returned by + `post_export_instance` will be passed to + `post_export_instance_with_metadata`. + """ + return response, metadata + def pre_failover_instance( self, request: cloud_redis.FailoverInstanceRequest, @@ -258,12 +327,35 @@ def post_failover_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for failover_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_failover_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_failover_instance` interceptor runs + before the `post_failover_instance_with_metadata` interceptor. """ return response + def post_failover_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for failover_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_failover_instance_with_metadata` + interceptor in new development instead of the `post_failover_instance` interceptor. + When both interceptors are used, this `post_failover_instance_with_metadata` interceptor runs after the + `post_failover_instance` interceptor. The (possibly modified) response returned by + `post_failover_instance` will be passed to + `post_failover_instance_with_metadata`. + """ + return response, metadata + def pre_get_instance( self, request: cloud_redis.GetInstanceRequest, @@ -279,12 +371,35 @@ def pre_get_instance( def post_get_instance(self, response: cloud_redis.Instance) -> cloud_redis.Instance: """Post-rpc interceptor for get_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_get_instance` interceptor runs + before the `post_get_instance_with_metadata` interceptor. """ return response + def post_get_instance_with_metadata( + self, + response: cloud_redis.Instance, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis.Instance, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_get_instance_with_metadata` + interceptor in new development instead of the `post_get_instance` interceptor. + When both interceptors are used, this `post_get_instance_with_metadata` interceptor runs after the + `post_get_instance` interceptor. The (possibly modified) response returned by + `post_get_instance` will be passed to + `post_get_instance_with_metadata`. + """ + return response, metadata + def pre_get_instance_auth_string( self, request: cloud_redis.GetInstanceAuthStringRequest, @@ -305,12 +420,35 @@ def post_get_instance_auth_string( ) -> cloud_redis.InstanceAuthString: """Post-rpc interceptor for get_instance_auth_string - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_instance_auth_string_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_get_instance_auth_string` interceptor runs + before the `post_get_instance_auth_string_with_metadata` interceptor. """ return response + def post_get_instance_auth_string_with_metadata( + self, + response: cloud_redis.InstanceAuthString, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis.InstanceAuthString, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_instance_auth_string + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_get_instance_auth_string_with_metadata` + interceptor in new development instead of the `post_get_instance_auth_string` interceptor. + When both interceptors are used, this `post_get_instance_auth_string_with_metadata` interceptor runs after the + `post_get_instance_auth_string` interceptor. The (possibly modified) response returned by + `post_get_instance_auth_string` will be passed to + `post_get_instance_auth_string_with_metadata`. + """ + return response, metadata + def pre_import_instance( self, request: cloud_redis.ImportInstanceRequest, @@ -330,12 +468,35 @@ def post_import_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_import_instance` interceptor runs + before the `post_import_instance_with_metadata` interceptor. """ return response + def post_import_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_import_instance_with_metadata` + interceptor in new development instead of the `post_import_instance` interceptor. + When both interceptors are used, this `post_import_instance_with_metadata` interceptor runs after the + `post_import_instance` interceptor. The (possibly modified) response returned by + `post_import_instance` will be passed to + `post_import_instance_with_metadata`. + """ + return response, metadata + def pre_list_instances( self, request: cloud_redis.ListInstancesRequest, @@ -355,12 +516,37 @@ def post_list_instances( ) -> cloud_redis.ListInstancesResponse: """Post-rpc interceptor for list_instances - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_instances_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_list_instances` interceptor runs + before the `post_list_instances_with_metadata` interceptor. """ return response + def post_list_instances_with_metadata( + self, + response: cloud_redis.ListInstancesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis.ListInstancesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_instances + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_list_instances_with_metadata` + interceptor in new development instead of the `post_list_instances` interceptor. + When both interceptors are used, this `post_list_instances_with_metadata` interceptor runs after the + `post_list_instances` interceptor. The (possibly modified) response returned by + `post_list_instances` will be passed to + `post_list_instances_with_metadata`. + """ + return response, metadata + def pre_reschedule_maintenance( self, request: cloud_redis.RescheduleMaintenanceRequest, @@ -381,12 +567,35 @@ def post_reschedule_maintenance( ) -> operations_pb2.Operation: """Post-rpc interceptor for reschedule_maintenance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_reschedule_maintenance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_reschedule_maintenance` interceptor runs + before the `post_reschedule_maintenance_with_metadata` interceptor. """ return response + def post_reschedule_maintenance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for reschedule_maintenance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_reschedule_maintenance_with_metadata` + interceptor in new development instead of the `post_reschedule_maintenance` interceptor. + When both interceptors are used, this `post_reschedule_maintenance_with_metadata` interceptor runs after the + `post_reschedule_maintenance` interceptor. The (possibly modified) response returned by + `post_reschedule_maintenance` will be passed to + `post_reschedule_maintenance_with_metadata`. + """ + return response, metadata + def pre_update_instance( self, request: cloud_redis.UpdateInstanceRequest, @@ -406,12 +615,35 @@ def post_update_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_update_instance` interceptor runs + before the `post_update_instance_with_metadata` interceptor. """ return response + def post_update_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_update_instance_with_metadata` + interceptor in new development instead of the `post_update_instance` interceptor. + When both interceptors are used, this `post_update_instance_with_metadata` interceptor runs after the + `post_update_instance` interceptor. The (possibly modified) response returned by + `post_update_instance` will be passed to + `post_update_instance_with_metadata`. + """ + return response, metadata + def pre_upgrade_instance( self, request: cloud_redis.UpgradeInstanceRequest, @@ -431,12 +663,35 @@ def post_upgrade_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for upgrade_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_upgrade_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_upgrade_instance` interceptor runs + before the `post_upgrade_instance_with_metadata` interceptor. """ return response + def post_upgrade_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for upgrade_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_upgrade_instance_with_metadata` + interceptor in new development instead of the `post_upgrade_instance` interceptor. + When both interceptors are used, this `post_upgrade_instance_with_metadata` interceptor runs after the + `post_upgrade_instance` interceptor. The (possibly modified) response returned by + `post_upgrade_instance` will be passed to + `post_upgrade_instance_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -872,6 +1127,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1016,6 +1275,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1168,6 +1431,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1318,6 +1585,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_failover_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_failover_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1463,6 +1734,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1606,6 +1881,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_instance_auth_string(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_instance_auth_string_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1758,6 +2037,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1905,6 +2188,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_instances(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_instances_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2057,6 +2344,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_reschedule_maintenance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_reschedule_maintenance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2209,6 +2500,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2359,6 +2654,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_upgrade_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_upgrade_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py index 6053ad2404bf..558c8aab67c5 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.17.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/client.py b/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/client.py index ed5ba91a16f3..ce5157634d44 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/client.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -510,6 +512,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/transports/rest.py b/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/transports/rest.py index c3d6149ea416..aba122c4f2c1 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/transports/rest.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1beta1/services/cloud_redis/transports/rest.py @@ -182,12 +182,35 @@ def post_create_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_create_instance` interceptor runs + before the `post_create_instance_with_metadata` interceptor. """ return response + def post_create_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_create_instance_with_metadata` + interceptor in new development instead of the `post_create_instance` interceptor. + When both interceptors are used, this `post_create_instance_with_metadata` interceptor runs after the + `post_create_instance` interceptor. The (possibly modified) response returned by + `post_create_instance` will be passed to + `post_create_instance_with_metadata`. + """ + return response, metadata + def pre_delete_instance( self, request: cloud_redis.DeleteInstanceRequest, @@ -207,12 +230,35 @@ def post_delete_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for delete_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_delete_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_delete_instance` interceptor runs + before the `post_delete_instance_with_metadata` interceptor. """ return response + def post_delete_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for delete_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_delete_instance_with_metadata` + interceptor in new development instead of the `post_delete_instance` interceptor. + When both interceptors are used, this `post_delete_instance_with_metadata` interceptor runs after the + `post_delete_instance` interceptor. The (possibly modified) response returned by + `post_delete_instance` will be passed to + `post_delete_instance_with_metadata`. + """ + return response, metadata + def pre_export_instance( self, request: cloud_redis.ExportInstanceRequest, @@ -232,12 +278,35 @@ def post_export_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_export_instance` interceptor runs + before the `post_export_instance_with_metadata` interceptor. """ return response + def post_export_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_export_instance_with_metadata` + interceptor in new development instead of the `post_export_instance` interceptor. + When both interceptors are used, this `post_export_instance_with_metadata` interceptor runs after the + `post_export_instance` interceptor. The (possibly modified) response returned by + `post_export_instance` will be passed to + `post_export_instance_with_metadata`. + """ + return response, metadata + def pre_failover_instance( self, request: cloud_redis.FailoverInstanceRequest, @@ -257,12 +326,35 @@ def post_failover_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for failover_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_failover_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_failover_instance` interceptor runs + before the `post_failover_instance_with_metadata` interceptor. """ return response + def post_failover_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for failover_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_failover_instance_with_metadata` + interceptor in new development instead of the `post_failover_instance` interceptor. + When both interceptors are used, this `post_failover_instance_with_metadata` interceptor runs after the + `post_failover_instance` interceptor. The (possibly modified) response returned by + `post_failover_instance` will be passed to + `post_failover_instance_with_metadata`. + """ + return response, metadata + def pre_get_instance( self, request: cloud_redis.GetInstanceRequest, @@ -278,12 +370,35 @@ def pre_get_instance( def post_get_instance(self, response: cloud_redis.Instance) -> cloud_redis.Instance: """Post-rpc interceptor for get_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_get_instance` interceptor runs + before the `post_get_instance_with_metadata` interceptor. """ return response + def post_get_instance_with_metadata( + self, + response: cloud_redis.Instance, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis.Instance, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_get_instance_with_metadata` + interceptor in new development instead of the `post_get_instance` interceptor. + When both interceptors are used, this `post_get_instance_with_metadata` interceptor runs after the + `post_get_instance` interceptor. The (possibly modified) response returned by + `post_get_instance` will be passed to + `post_get_instance_with_metadata`. + """ + return response, metadata + def pre_get_instance_auth_string( self, request: cloud_redis.GetInstanceAuthStringRequest, @@ -304,12 +419,35 @@ def post_get_instance_auth_string( ) -> cloud_redis.InstanceAuthString: """Post-rpc interceptor for get_instance_auth_string - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_instance_auth_string_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_get_instance_auth_string` interceptor runs + before the `post_get_instance_auth_string_with_metadata` interceptor. """ return response + def post_get_instance_auth_string_with_metadata( + self, + response: cloud_redis.InstanceAuthString, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[cloud_redis.InstanceAuthString, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_instance_auth_string + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_get_instance_auth_string_with_metadata` + interceptor in new development instead of the `post_get_instance_auth_string` interceptor. + When both interceptors are used, this `post_get_instance_auth_string_with_metadata` interceptor runs after the + `post_get_instance_auth_string` interceptor. The (possibly modified) response returned by + `post_get_instance_auth_string` will be passed to + `post_get_instance_auth_string_with_metadata`. + """ + return response, metadata + def pre_import_instance( self, request: cloud_redis.ImportInstanceRequest, @@ -329,12 +467,35 @@ def post_import_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_import_instance` interceptor runs + before the `post_import_instance_with_metadata` interceptor. """ return response + def post_import_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_import_instance_with_metadata` + interceptor in new development instead of the `post_import_instance` interceptor. + When both interceptors are used, this `post_import_instance_with_metadata` interceptor runs after the + `post_import_instance` interceptor. The (possibly modified) response returned by + `post_import_instance` will be passed to + `post_import_instance_with_metadata`. + """ + return response, metadata + def pre_list_instances( self, request: cloud_redis.ListInstancesRequest, @@ -354,12 +515,37 @@ def post_list_instances( ) -> cloud_redis.ListInstancesResponse: """Post-rpc interceptor for list_instances - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_instances_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_list_instances` interceptor runs + before the `post_list_instances_with_metadata` interceptor. """ return response + def post_list_instances_with_metadata( + self, + response: cloud_redis.ListInstancesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloud_redis.ListInstancesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_instances + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_list_instances_with_metadata` + interceptor in new development instead of the `post_list_instances` interceptor. + When both interceptors are used, this `post_list_instances_with_metadata` interceptor runs after the + `post_list_instances` interceptor. The (possibly modified) response returned by + `post_list_instances` will be passed to + `post_list_instances_with_metadata`. + """ + return response, metadata + def pre_reschedule_maintenance( self, request: cloud_redis.RescheduleMaintenanceRequest, @@ -380,12 +566,35 @@ def post_reschedule_maintenance( ) -> operations_pb2.Operation: """Post-rpc interceptor for reschedule_maintenance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_reschedule_maintenance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_reschedule_maintenance` interceptor runs + before the `post_reschedule_maintenance_with_metadata` interceptor. """ return response + def post_reschedule_maintenance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for reschedule_maintenance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_reschedule_maintenance_with_metadata` + interceptor in new development instead of the `post_reschedule_maintenance` interceptor. + When both interceptors are used, this `post_reschedule_maintenance_with_metadata` interceptor runs after the + `post_reschedule_maintenance` interceptor. The (possibly modified) response returned by + `post_reschedule_maintenance` will be passed to + `post_reschedule_maintenance_with_metadata`. + """ + return response, metadata + def pre_update_instance( self, request: cloud_redis.UpdateInstanceRequest, @@ -405,12 +614,35 @@ def post_update_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for update_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_update_instance` interceptor runs + before the `post_update_instance_with_metadata` interceptor. """ return response + def post_update_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_update_instance_with_metadata` + interceptor in new development instead of the `post_update_instance` interceptor. + When both interceptors are used, this `post_update_instance_with_metadata` interceptor runs after the + `post_update_instance` interceptor. The (possibly modified) response returned by + `post_update_instance` will be passed to + `post_update_instance_with_metadata`. + """ + return response, metadata + def pre_upgrade_instance( self, request: cloud_redis.UpgradeInstanceRequest, @@ -430,12 +662,35 @@ def post_upgrade_instance( ) -> operations_pb2.Operation: """Post-rpc interceptor for upgrade_instance - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_upgrade_instance_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudRedis server but before - it is returned to user code. + it is returned to user code. This `post_upgrade_instance` interceptor runs + before the `post_upgrade_instance_with_metadata` interceptor. """ return response + def post_upgrade_instance_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for upgrade_instance + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudRedis server but before it is returned to user code. + + We recommend only using this `post_upgrade_instance_with_metadata` + interceptor in new development instead of the `post_upgrade_instance` interceptor. + When both interceptors are used, this `post_upgrade_instance_with_metadata` interceptor runs after the + `post_upgrade_instance` interceptor. The (possibly modified) response returned by + `post_upgrade_instance` will be passed to + `post_upgrade_instance_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class CloudRedisRestStub: @@ -725,6 +980,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -869,6 +1128,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_delete_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_delete_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1021,6 +1284,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1171,6 +1438,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_failover_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_failover_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1316,6 +1587,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1459,6 +1734,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_instance_auth_string(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_instance_auth_string_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1611,6 +1890,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1758,6 +2041,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_instances(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_instances_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1910,6 +2197,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_reschedule_maintenance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_reschedule_maintenance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2062,6 +2353,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2212,6 +2507,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_upgrade_instance(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_upgrade_instance_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-redis/noxfile.py b/packages/google-cloud-redis/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-redis/noxfile.py +++ b/packages/google-cloud-redis/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json index 9edeb020e1bf..78f872bc4aef 100644 --- a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json +++ b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis", - "version": "2.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json index 41dee5d65dba..e1412dd446e5 100644 --- a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json +++ b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis", - "version": "2.17.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis/tests/unit/gapic/redis_v1/test_cloud_redis.py b/packages/google-cloud-redis/tests/unit/gapic/redis_v1/test_cloud_redis.py index a18ae66530de..abe46a8af1b8 100644 --- a/packages/google-cloud-redis/tests/unit/gapic/redis_v1/test_cloud_redis.py +++ b/packages/google-cloud-redis/tests/unit/gapic/redis_v1/test_cloud_redis.py @@ -77,6 +77,13 @@ ) from google.cloud.redis_v1.types import cloud_redis +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -312,6 +319,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudRedisClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudRedisClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -8037,10 +8087,13 @@ def test_list_instances_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_list_instances" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_list_instances_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_list_instances" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ListInstancesRequest.pb( cloud_redis.ListInstancesRequest() ) @@ -8066,6 +8119,7 @@ def test_list_instances_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.ListInstancesResponse() + post_with_metadata.return_value = cloud_redis.ListInstancesResponse(), metadata client.list_instances( request, @@ -8077,6 +8131,7 @@ def test_list_instances_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_instance_rest_bad_request(request_type=cloud_redis.GetInstanceRequest): @@ -8223,10 +8278,13 @@ def test_get_instance_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_get_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_get_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_get_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.GetInstanceRequest.pb(cloud_redis.GetInstanceRequest()) transcode.return_value = { "method": "post", @@ -8248,6 +8306,7 @@ def test_get_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.Instance() + post_with_metadata.return_value = cloud_redis.Instance(), metadata client.get_instance( request, @@ -8259,6 +8318,7 @@ def test_get_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_instance_auth_string_rest_bad_request( @@ -8343,10 +8403,14 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_get_instance_auth_string" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, + "post_get_instance_auth_string_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_get_instance_auth_string" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.GetInstanceAuthStringRequest.pb( cloud_redis.GetInstanceAuthStringRequest() ) @@ -8372,6 +8436,7 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.InstanceAuthString() + post_with_metadata.return_value = cloud_redis.InstanceAuthString(), metadata client.get_instance_auth_string( request, @@ -8383,6 +8448,7 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_instance_rest_bad_request( @@ -8604,10 +8670,13 @@ def test_create_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_create_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_create_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_create_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.CreateInstanceRequest.pb( cloud_redis.CreateInstanceRequest() ) @@ -8631,6 +8700,7 @@ def test_create_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_instance( request, @@ -8642,6 +8712,7 @@ def test_create_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_instance_rest_bad_request( @@ -8867,10 +8938,13 @@ def test_update_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_update_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_update_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_update_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.UpdateInstanceRequest.pb( cloud_redis.UpdateInstanceRequest() ) @@ -8894,6 +8968,7 @@ def test_update_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_instance( request, @@ -8905,6 +8980,7 @@ def test_update_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_upgrade_instance_rest_bad_request( @@ -8985,10 +9061,13 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_upgrade_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_upgrade_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_upgrade_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.UpgradeInstanceRequest.pb( cloud_redis.UpgradeInstanceRequest() ) @@ -9012,6 +9091,7 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.upgrade_instance( request, @@ -9023,6 +9103,7 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_instance_rest_bad_request( @@ -9103,10 +9184,13 @@ def test_import_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_import_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_import_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_import_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ImportInstanceRequest.pb( cloud_redis.ImportInstanceRequest() ) @@ -9130,6 +9214,7 @@ def test_import_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_instance( request, @@ -9141,6 +9226,7 @@ def test_import_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_instance_rest_bad_request( @@ -9221,10 +9307,13 @@ def test_export_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_export_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_export_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_export_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ExportInstanceRequest.pb( cloud_redis.ExportInstanceRequest() ) @@ -9248,6 +9337,7 @@ def test_export_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_instance( request, @@ -9259,6 +9349,7 @@ def test_export_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_failover_instance_rest_bad_request( @@ -9339,10 +9430,13 @@ def test_failover_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_failover_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_failover_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_failover_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.FailoverInstanceRequest.pb( cloud_redis.FailoverInstanceRequest() ) @@ -9366,6 +9460,7 @@ def test_failover_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.failover_instance( request, @@ -9377,6 +9472,7 @@ def test_failover_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_instance_rest_bad_request( @@ -9457,10 +9553,13 @@ def test_delete_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_delete_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_delete_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_delete_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.DeleteInstanceRequest.pb( cloud_redis.DeleteInstanceRequest() ) @@ -9484,6 +9583,7 @@ def test_delete_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_instance( request, @@ -9495,6 +9595,7 @@ def test_delete_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_reschedule_maintenance_rest_bad_request( @@ -9575,10 +9676,14 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_reschedule_maintenance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, + "post_reschedule_maintenance_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_reschedule_maintenance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.RescheduleMaintenanceRequest.pb( cloud_redis.RescheduleMaintenanceRequest() ) @@ -9602,6 +9707,7 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.reschedule_maintenance( request, @@ -9613,6 +9719,7 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-redis/tests/unit/gapic/redis_v1beta1/test_cloud_redis.py b/packages/google-cloud-redis/tests/unit/gapic/redis_v1beta1/test_cloud_redis.py index c40f00572e24..a5e5171cad3b 100644 --- a/packages/google-cloud-redis/tests/unit/gapic/redis_v1beta1/test_cloud_redis.py +++ b/packages/google-cloud-redis/tests/unit/gapic/redis_v1beta1/test_cloud_redis.py @@ -77,6 +77,13 @@ ) from google.cloud.redis_v1beta1.types import cloud_redis +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -312,6 +319,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudRedisClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudRedisClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -8007,10 +8057,13 @@ def test_list_instances_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_list_instances" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_list_instances_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_list_instances" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ListInstancesRequest.pb( cloud_redis.ListInstancesRequest() ) @@ -8036,6 +8089,7 @@ def test_list_instances_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.ListInstancesResponse() + post_with_metadata.return_value = cloud_redis.ListInstancesResponse(), metadata client.list_instances( request, @@ -8047,6 +8101,7 @@ def test_list_instances_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_instance_rest_bad_request(request_type=cloud_redis.GetInstanceRequest): @@ -8179,10 +8234,13 @@ def test_get_instance_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_get_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_get_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_get_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.GetInstanceRequest.pb(cloud_redis.GetInstanceRequest()) transcode.return_value = { "method": "post", @@ -8204,6 +8262,7 @@ def test_get_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.Instance() + post_with_metadata.return_value = cloud_redis.Instance(), metadata client.get_instance( request, @@ -8215,6 +8274,7 @@ def test_get_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_instance_auth_string_rest_bad_request( @@ -8299,10 +8359,14 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudRedisRestInterceptor, "post_get_instance_auth_string" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, + "post_get_instance_auth_string_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_get_instance_auth_string" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.GetInstanceAuthStringRequest.pb( cloud_redis.GetInstanceAuthStringRequest() ) @@ -8328,6 +8392,7 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloud_redis.InstanceAuthString() + post_with_metadata.return_value = cloud_redis.InstanceAuthString(), metadata client.get_instance_auth_string( request, @@ -8339,6 +8404,7 @@ def test_get_instance_auth_string_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_instance_rest_bad_request( @@ -8553,10 +8619,13 @@ def test_create_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_create_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_create_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_create_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.CreateInstanceRequest.pb( cloud_redis.CreateInstanceRequest() ) @@ -8580,6 +8649,7 @@ def test_create_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_instance( request, @@ -8591,6 +8661,7 @@ def test_create_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_instance_rest_bad_request( @@ -8809,10 +8880,13 @@ def test_update_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_update_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_update_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_update_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.UpdateInstanceRequest.pb( cloud_redis.UpdateInstanceRequest() ) @@ -8836,6 +8910,7 @@ def test_update_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.update_instance( request, @@ -8847,6 +8922,7 @@ def test_update_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_upgrade_instance_rest_bad_request( @@ -8927,10 +9003,13 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_upgrade_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_upgrade_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_upgrade_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.UpgradeInstanceRequest.pb( cloud_redis.UpgradeInstanceRequest() ) @@ -8954,6 +9033,7 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.upgrade_instance( request, @@ -8965,6 +9045,7 @@ def test_upgrade_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_instance_rest_bad_request( @@ -9045,10 +9126,13 @@ def test_import_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_import_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_import_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_import_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ImportInstanceRequest.pb( cloud_redis.ImportInstanceRequest() ) @@ -9072,6 +9156,7 @@ def test_import_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_instance( request, @@ -9083,6 +9168,7 @@ def test_import_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_instance_rest_bad_request( @@ -9163,10 +9249,13 @@ def test_export_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_export_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_export_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_export_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.ExportInstanceRequest.pb( cloud_redis.ExportInstanceRequest() ) @@ -9190,6 +9279,7 @@ def test_export_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_instance( request, @@ -9201,6 +9291,7 @@ def test_export_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_failover_instance_rest_bad_request( @@ -9281,10 +9372,13 @@ def test_failover_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_failover_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_failover_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_failover_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.FailoverInstanceRequest.pb( cloud_redis.FailoverInstanceRequest() ) @@ -9308,6 +9402,7 @@ def test_failover_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.failover_instance( request, @@ -9319,6 +9414,7 @@ def test_failover_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_instance_rest_bad_request( @@ -9399,10 +9495,13 @@ def test_delete_instance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_delete_instance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, "post_delete_instance_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_delete_instance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.DeleteInstanceRequest.pb( cloud_redis.DeleteInstanceRequest() ) @@ -9426,6 +9525,7 @@ def test_delete_instance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.delete_instance( request, @@ -9437,6 +9537,7 @@ def test_delete_instance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_reschedule_maintenance_rest_bad_request( @@ -9517,10 +9618,14 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CloudRedisRestInterceptor, "post_reschedule_maintenance" ) as post, mock.patch.object( + transports.CloudRedisRestInterceptor, + "post_reschedule_maintenance_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CloudRedisRestInterceptor, "pre_reschedule_maintenance" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloud_redis.RescheduleMaintenanceRequest.pb( cloud_redis.RescheduleMaintenanceRequest() ) @@ -9544,6 +9649,7 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.reschedule_maintenance( request, @@ -9555,6 +9661,7 @@ def test_reschedule_maintenance_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-resource-settings/README.rst b/packages/google-cloud-resource-settings/README.rst index fb1757cda5dc..2e520f84f964 100644 --- a/packages/google-cloud-resource-settings/README.rst +++ b/packages/google-cloud-resource-settings/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Resource Settings.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Resource Settings.: https://cloud.google.com/resource-manager/docs/reference/resource-settings/rest -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py index 50d842f376d0..558c8aab67c5 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.11.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py index 50d842f376d0..558c8aab67c5 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.11.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/client.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/client.py index 58b17256d332..6daa80582df4 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/client.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -500,6 +502,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/transports/rest.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/transports/rest.py index 2d86da54e90c..58a14793934e 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/transports/rest.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/services/resource_settings_service/transports/rest.py @@ -117,12 +117,35 @@ def post_get_setting( ) -> resource_settings.Setting: """Post-rpc interceptor for get_setting - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_setting_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ResourceSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_get_setting` interceptor runs + before the `post_get_setting_with_metadata` interceptor. """ return response + def post_get_setting_with_metadata( + self, + response: resource_settings.Setting, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resource_settings.Setting, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_setting + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ResourceSettingsService server but before it is returned to user code. + + We recommend only using this `post_get_setting_with_metadata` + interceptor in new development instead of the `post_get_setting` interceptor. + When both interceptors are used, this `post_get_setting_with_metadata` interceptor runs after the + `post_get_setting` interceptor. The (possibly modified) response returned by + `post_get_setting` will be passed to + `post_get_setting_with_metadata`. + """ + return response, metadata + def pre_list_settings( self, request: resource_settings.ListSettingsRequest, @@ -142,12 +165,37 @@ def post_list_settings( ) -> resource_settings.ListSettingsResponse: """Post-rpc interceptor for list_settings - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_settings_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ResourceSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_list_settings` interceptor runs + before the `post_list_settings_with_metadata` interceptor. """ return response + def post_list_settings_with_metadata( + self, + response: resource_settings.ListSettingsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + resource_settings.ListSettingsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_settings + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ResourceSettingsService server but before it is returned to user code. + + We recommend only using this `post_list_settings_with_metadata` + interceptor in new development instead of the `post_list_settings` interceptor. + When both interceptors are used, this `post_list_settings_with_metadata` interceptor runs after the + `post_list_settings` interceptor. The (possibly modified) response returned by + `post_list_settings` will be passed to + `post_list_settings_with_metadata`. + """ + return response, metadata + def pre_update_setting( self, request: resource_settings.UpdateSettingRequest, @@ -167,12 +215,35 @@ def post_update_setting( ) -> resource_settings.Setting: """Post-rpc interceptor for update_setting - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_setting_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ResourceSettingsService server but before - it is returned to user code. + it is returned to user code. This `post_update_setting` interceptor runs + before the `post_update_setting_with_metadata` interceptor. """ return response + def post_update_setting_with_metadata( + self, + response: resource_settings.Setting, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[resource_settings.Setting, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_setting + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ResourceSettingsService server but before it is returned to user code. + + We recommend only using this `post_update_setting_with_metadata` + interceptor in new development instead of the `post_update_setting` interceptor. + When both interceptors are used, this `post_update_setting_with_metadata` interceptor runs after the + `post_update_setting` interceptor. The (possibly modified) response returned by + `post_update_setting` will be passed to + `post_update_setting_with_metadata`. + """ + return response, metadata + @dataclasses.dataclass class ResourceSettingsServiceRestStub: @@ -394,6 +465,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_setting(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_setting_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -535,6 +610,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_settings(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_settings_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -686,6 +765,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_setting(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_setting_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-resource-settings/noxfile.py b/packages/google-cloud-resource-settings/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-resource-settings/noxfile.py +++ b/packages/google-cloud-resource-settings/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json b/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json index ce326c30070c..61a2b1d93fba 100644 --- a/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json +++ b/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-resource-settings", - "version": "1.11.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-resource-settings/tests/unit/gapic/resourcesettings_v1/test_resource_settings_service.py b/packages/google-cloud-resource-settings/tests/unit/gapic/resourcesettings_v1/test_resource_settings_service.py index 3b9ad3ebf0e9..c3c42181338c 100644 --- a/packages/google-cloud-resource-settings/tests/unit/gapic/resourcesettings_v1/test_resource_settings_service.py +++ b/packages/google-cloud-resource-settings/tests/unit/gapic/resourcesettings_v1/test_resource_settings_service.py @@ -60,6 +60,13 @@ ) from google.cloud.resourcesettings_v1.types import resource_settings +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -335,6 +342,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ResourceSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ResourceSettingsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3116,10 +3166,14 @@ def test_list_settings_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "post_list_settings" ) as post, mock.patch.object( + transports.ResourceSettingsServiceRestInterceptor, + "post_list_settings_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "pre_list_settings" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = resource_settings.ListSettingsRequest.pb( resource_settings.ListSettingsRequest() ) @@ -3145,6 +3199,10 @@ def test_list_settings_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resource_settings.ListSettingsResponse() + post_with_metadata.return_value = ( + resource_settings.ListSettingsResponse(), + metadata, + ) client.list_settings( request, @@ -3156,6 +3214,7 @@ def test_list_settings_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_setting_rest_bad_request(request_type=resource_settings.GetSettingRequest): @@ -3240,10 +3299,14 @@ def test_get_setting_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "post_get_setting" ) as post, mock.patch.object( + transports.ResourceSettingsServiceRestInterceptor, + "post_get_setting_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "pre_get_setting" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = resource_settings.GetSettingRequest.pb( resource_settings.GetSettingRequest() ) @@ -3267,6 +3330,7 @@ def test_get_setting_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resource_settings.Setting() + post_with_metadata.return_value = resource_settings.Setting(), metadata client.get_setting( request, @@ -3278,6 +3342,7 @@ def test_get_setting_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_setting_rest_bad_request( @@ -3449,10 +3514,14 @@ def test_update_setting_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "post_update_setting" ) as post, mock.patch.object( + transports.ResourceSettingsServiceRestInterceptor, + "post_update_setting_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ResourceSettingsServiceRestInterceptor, "pre_update_setting" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = resource_settings.UpdateSettingRequest.pb( resource_settings.UpdateSettingRequest() ) @@ -3476,6 +3545,7 @@ def test_update_setting_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = resource_settings.Setting() + post_with_metadata.return_value = resource_settings.Setting(), metadata client.update_setting( request, @@ -3487,6 +3557,7 @@ def test_update_setting_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_initialize_client_w_rest(): diff --git a/packages/google-cloud-retail/README.rst b/packages/google-cloud-retail/README.rst index 8a9ab62dd142..5c7965483ef1 100644 --- a/packages/google-cloud-retail/README.rst +++ b/packages/google-cloud-retail/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Retail.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Retail.: https://cloud.google.com/retail/docs/ -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-retail/google/cloud/retail/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail/gapic_version.py index 45f4e360312c..558c8aab67c5 100644 --- a/packages/google-cloud-retail/google/cloud/retail/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.24.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py index 45f4e360312c..558c8aab67c5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.24.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/client.py index a70574add3e6..d746ea868df5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -469,6 +471,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/transports/rest.py index 7bf0c24abd39..7898f9c4ebcf 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/analytics_service/transports/rest.py @@ -104,12 +104,35 @@ def post_export_analytics_metrics( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_analytics_metrics - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_analytics_metrics_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AnalyticsService server but before - it is returned to user code. + it is returned to user code. This `post_export_analytics_metrics` interceptor runs + before the `post_export_analytics_metrics_with_metadata` interceptor. """ return response + def post_export_analytics_metrics_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_analytics_metrics + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AnalyticsService server but before it is returned to user code. + + We recommend only using this `post_export_analytics_metrics_with_metadata` + interceptor in new development instead of the `post_export_analytics_metrics` interceptor. + When both interceptors are used, this `post_export_analytics_metrics_with_metadata` interceptor runs after the + `post_export_analytics_metrics` interceptor. The (possibly modified) response returned by + `post_export_analytics_metrics` will be passed to + `post_export_analytics_metrics_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -440,6 +463,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_analytics_metrics(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_analytics_metrics_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/client.py index d0dd424a320d..f3e4b3f26530 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -559,6 +561,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2091,16 +2120,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2146,16 +2179,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/transports/rest.py index 4be2d925f4b7..ac774447e792 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/catalog_service/transports/rest.py @@ -183,12 +183,35 @@ def post_add_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for add_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_add_catalog_attribute` interceptor runs + before the `post_add_catalog_attribute_with_metadata` interceptor. """ return response + def post_add_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_add_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_add_catalog_attribute` interceptor. + When both interceptors are used, this `post_add_catalog_attribute_with_metadata` interceptor runs after the + `post_add_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_add_catalog_attribute` will be passed to + `post_add_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_get_attributes_config( self, request: catalog_service.GetAttributesConfigRequest, @@ -209,12 +232,35 @@ def post_get_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for get_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_attributes_config` interceptor runs + before the `post_get_attributes_config_with_metadata` interceptor. """ return response + def post_get_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_attributes_config_with_metadata` + interceptor in new development instead of the `post_get_attributes_config` interceptor. + When both interceptors are used, this `post_get_attributes_config_with_metadata` interceptor runs after the + `post_get_attributes_config` interceptor. The (possibly modified) response returned by + `post_get_attributes_config` will be passed to + `post_get_attributes_config_with_metadata`. + """ + return response, metadata + def pre_get_completion_config( self, request: catalog_service.GetCompletionConfigRequest, @@ -235,12 +281,35 @@ def post_get_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for get_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_completion_config` interceptor runs + before the `post_get_completion_config_with_metadata` interceptor. """ return response + def post_get_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_completion_config_with_metadata` + interceptor in new development instead of the `post_get_completion_config` interceptor. + When both interceptors are used, this `post_get_completion_config_with_metadata` interceptor runs after the + `post_get_completion_config` interceptor. The (possibly modified) response returned by + `post_get_completion_config` will be passed to + `post_get_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_default_branch( self, request: catalog_service.GetDefaultBranchRequest, @@ -260,12 +329,38 @@ def post_get_default_branch( ) -> catalog_service.GetDefaultBranchResponse: """Post-rpc interceptor for get_default_branch - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_default_branch_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_default_branch` interceptor runs + before the `post_get_default_branch_with_metadata` interceptor. """ return response + def post_get_default_branch_with_metadata( + self, + response: catalog_service.GetDefaultBranchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.GetDefaultBranchResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_default_branch + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_default_branch_with_metadata` + interceptor in new development instead of the `post_get_default_branch` interceptor. + When both interceptors are used, this `post_get_default_branch_with_metadata` interceptor runs after the + `post_get_default_branch` interceptor. The (possibly modified) response returned by + `post_get_default_branch` will be passed to + `post_get_default_branch_with_metadata`. + """ + return response, metadata + def pre_list_catalogs( self, request: catalog_service.ListCatalogsRequest, @@ -285,12 +380,37 @@ def post_list_catalogs( ) -> catalog_service.ListCatalogsResponse: """Post-rpc interceptor for list_catalogs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_catalogs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_list_catalogs` interceptor runs + before the `post_list_catalogs_with_metadata` interceptor. """ return response + def post_list_catalogs_with_metadata( + self, + response: catalog_service.ListCatalogsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.ListCatalogsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_catalogs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_list_catalogs_with_metadata` + interceptor in new development instead of the `post_list_catalogs` interceptor. + When both interceptors are used, this `post_list_catalogs_with_metadata` interceptor runs after the + `post_list_catalogs` interceptor. The (possibly modified) response returned by + `post_list_catalogs` will be passed to + `post_list_catalogs_with_metadata`. + """ + return response, metadata + def pre_remove_catalog_attribute( self, request: catalog_service.RemoveCatalogAttributeRequest, @@ -311,12 +431,35 @@ def post_remove_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for remove_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_remove_catalog_attribute` interceptor runs + before the `post_remove_catalog_attribute_with_metadata` interceptor. """ return response + def post_remove_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_remove_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_remove_catalog_attribute` interceptor. + When both interceptors are used, this `post_remove_catalog_attribute_with_metadata` interceptor runs after the + `post_remove_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_remove_catalog_attribute` will be passed to + `post_remove_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_replace_catalog_attribute( self, request: catalog_service.ReplaceCatalogAttributeRequest, @@ -337,12 +480,35 @@ def post_replace_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for replace_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_replace_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_replace_catalog_attribute` interceptor runs + before the `post_replace_catalog_attribute_with_metadata` interceptor. """ return response + def post_replace_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for replace_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_replace_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_replace_catalog_attribute` interceptor. + When both interceptors are used, this `post_replace_catalog_attribute_with_metadata` interceptor runs after the + `post_replace_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_replace_catalog_attribute` will be passed to + `post_replace_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_set_default_branch( self, request: catalog_service.SetDefaultBranchRequest, @@ -377,12 +543,35 @@ def post_update_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for update_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_attributes_config` interceptor runs + before the `post_update_attributes_config_with_metadata` interceptor. """ return response + def post_update_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_attributes_config_with_metadata` + interceptor in new development instead of the `post_update_attributes_config` interceptor. + When both interceptors are used, this `post_update_attributes_config_with_metadata` interceptor runs after the + `post_update_attributes_config` interceptor. The (possibly modified) response returned by + `post_update_attributes_config` will be passed to + `post_update_attributes_config_with_metadata`. + """ + return response, metadata + def pre_update_catalog( self, request: catalog_service.UpdateCatalogRequest, @@ -400,12 +589,35 @@ def pre_update_catalog( def post_update_catalog(self, response: gcr_catalog.Catalog) -> gcr_catalog.Catalog: """Post-rpc interceptor for update_catalog - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_catalog_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_catalog` interceptor runs + before the `post_update_catalog_with_metadata` interceptor. """ return response + def post_update_catalog_with_metadata( + self, + response: gcr_catalog.Catalog, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_catalog.Catalog, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_catalog + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_catalog_with_metadata` + interceptor in new development instead of the `post_update_catalog` interceptor. + When both interceptors are used, this `post_update_catalog_with_metadata` interceptor runs after the + `post_update_catalog` interceptor. The (possibly modified) response returned by + `post_update_catalog` will be passed to + `post_update_catalog_with_metadata`. + """ + return response, metadata + def pre_update_completion_config( self, request: catalog_service.UpdateCompletionConfigRequest, @@ -426,12 +638,35 @@ def post_update_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for update_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_completion_config` interceptor runs + before the `post_update_completion_config_with_metadata` interceptor. """ return response + def post_update_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_completion_config_with_metadata` + interceptor in new development instead of the `post_update_completion_config` interceptor. + When both interceptors are used, this `post_update_completion_config_with_metadata` interceptor runs after the + `post_update_completion_config` interceptor. The (possibly modified) response returned by + `post_update_completion_config` will be passed to + `post_update_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -697,6 +932,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -842,6 +1081,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -990,6 +1233,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1135,6 +1382,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_default_branch(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_default_branch_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1282,6 +1533,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_catalogs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_catalogs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1437,6 +1692,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1590,6 +1849,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_replace_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_replace_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1858,6 +2121,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2006,6 +2273,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_catalog(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_catalog_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2162,6 +2433,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/client.py index 63d95438b42f..0c96f8a9dcaa 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -493,6 +495,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -957,16 +986,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1012,16 +1045,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/transports/rest.py index c36cf8588f7d..cc1bb4145ec2 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/completion_service/transports/rest.py @@ -111,12 +111,38 @@ def post_complete_query( ) -> completion_service.CompleteQueryResponse: """Post-rpc interceptor for complete_query - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_complete_query_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_complete_query` interceptor runs + before the `post_complete_query_with_metadata` interceptor. """ return response + def post_complete_query_with_metadata( + self, + response: completion_service.CompleteQueryResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + completion_service.CompleteQueryResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for complete_query + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_complete_query_with_metadata` + interceptor in new development instead of the `post_complete_query` interceptor. + When both interceptors are used, this `post_complete_query_with_metadata` interceptor runs after the + `post_complete_query` interceptor. The (possibly modified) response returned by + `post_complete_query` will be passed to + `post_complete_query_with_metadata`. + """ + return response, metadata + def pre_import_completion_data( self, request: import_config.ImportCompletionDataRequest, @@ -137,12 +163,35 @@ def post_import_completion_data( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_completion_data - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_completion_data_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_import_completion_data` interceptor runs + before the `post_import_completion_data_with_metadata` interceptor. """ return response + def post_import_completion_data_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_completion_data + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_import_completion_data_with_metadata` + interceptor in new development instead of the `post_import_completion_data` interceptor. + When both interceptors are used, this `post_import_completion_data_with_metadata` interceptor runs after the + `post_import_completion_data` interceptor. The (possibly modified) response returned by + `post_import_completion_data` will be passed to + `post_import_completion_data_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -463,6 +512,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_complete_query(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_complete_query_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -618,6 +671,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_completion_data(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_completion_data_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/client.py index 2a5578694972..9ad9e5337bcd 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1358,16 +1387,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1413,16 +1446,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/transports/rest.py index 2eb5ac2151c1..c7567cf287e9 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/control_service/transports/rest.py @@ -132,12 +132,35 @@ def pre_create_control( def post_create_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for create_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_create_control` interceptor runs + before the `post_create_control_with_metadata` interceptor. """ return response + def post_create_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_create_control_with_metadata` + interceptor in new development instead of the `post_create_control` interceptor. + When both interceptors are used, this `post_create_control_with_metadata` interceptor runs after the + `post_create_control` interceptor. The (possibly modified) response returned by + `post_create_control` will be passed to + `post_create_control_with_metadata`. + """ + return response, metadata + def pre_delete_control( self, request: control_service.DeleteControlRequest, @@ -169,12 +192,35 @@ def pre_get_control( def post_get_control(self, response: control.Control) -> control.Control: """Post-rpc interceptor for get_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_get_control` interceptor runs + before the `post_get_control_with_metadata` interceptor. """ return response + def post_get_control_with_metadata( + self, + response: control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_get_control_with_metadata` + interceptor in new development instead of the `post_get_control` interceptor. + When both interceptors are used, this `post_get_control_with_metadata` interceptor runs after the + `post_get_control` interceptor. The (possibly modified) response returned by + `post_get_control` will be passed to + `post_get_control_with_metadata`. + """ + return response, metadata + def pre_list_controls( self, request: control_service.ListControlsRequest, @@ -194,12 +240,37 @@ def post_list_controls( ) -> control_service.ListControlsResponse: """Post-rpc interceptor for list_controls - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_controls_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_list_controls` interceptor runs + before the `post_list_controls_with_metadata` interceptor. """ return response + def post_list_controls_with_metadata( + self, + response: control_service.ListControlsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + control_service.ListControlsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_controls + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_list_controls_with_metadata` + interceptor in new development instead of the `post_list_controls` interceptor. + When both interceptors are used, this `post_list_controls_with_metadata` interceptor runs after the + `post_list_controls` interceptor. The (possibly modified) response returned by + `post_list_controls` will be passed to + `post_list_controls_with_metadata`. + """ + return response, metadata + def pre_update_control( self, request: control_service.UpdateControlRequest, @@ -217,12 +288,35 @@ def pre_update_control( def post_update_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for update_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_update_control` interceptor runs + before the `post_update_control_with_metadata` interceptor. """ return response + def post_update_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_update_control_with_metadata` + interceptor in new development instead of the `post_update_control` interceptor. + When both interceptors are used, this `post_update_control_with_metadata` interceptor runs after the + `post_update_control` interceptor. The (possibly modified) response returned by + `post_update_control` will be passed to + `post_update_control_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -487,6 +581,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -739,6 +837,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -879,6 +981,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_controls(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_controls_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1031,6 +1137,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/client.py index 520c30ce2d69..0ccb12932c1d 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -494,6 +496,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1414,16 +1443,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1469,16 +1502,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/transports/rest.py index 0dac17153323..298ca90305ed 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/generative_question_service/transports/rest.py @@ -140,12 +140,38 @@ def post_batch_update_generative_question_configs( ) -> generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse: """Post-rpc interceptor for batch_update_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_update_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_batch_update_generative_question_configs` interceptor runs + before the `post_batch_update_generative_question_configs_with_metadata` interceptor. """ return response + def post_batch_update_generative_question_configs_with_metadata( + self, + response: generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for batch_update_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_batch_update_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_batch_update_generative_question_configs` interceptor. + When both interceptors are used, this `post_batch_update_generative_question_configs_with_metadata` interceptor runs after the + `post_batch_update_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_batch_update_generative_question_configs` will be passed to + `post_batch_update_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_get_generative_questions_feature_config( self, request: generative_question_service.GetGenerativeQuestionsFeatureConfigRequest, @@ -166,12 +192,38 @@ def post_get_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for get_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_get_generative_questions_feature_config` interceptor runs + before the `post_get_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_get_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_get_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_get_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_get_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_get_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_get_generative_questions_feature_config` will be passed to + `post_get_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_list_generative_question_configs( self, request: generative_question_service.ListGenerativeQuestionConfigsRequest, @@ -193,12 +245,38 @@ def post_list_generative_question_configs( ) -> generative_question_service.ListGenerativeQuestionConfigsResponse: """Post-rpc interceptor for list_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_list_generative_question_configs` interceptor runs + before the `post_list_generative_question_configs_with_metadata` interceptor. """ return response + def post_list_generative_question_configs_with_metadata( + self, + response: generative_question_service.ListGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.ListGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_list_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_list_generative_question_configs` interceptor. + When both interceptors are used, this `post_list_generative_question_configs_with_metadata` interceptor runs after the + `post_list_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_list_generative_question_configs` will be passed to + `post_list_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_update_generative_question_config( self, request: generative_question_service.UpdateGenerativeQuestionConfigRequest, @@ -219,12 +297,38 @@ def post_update_generative_question_config( ) -> generative_question.GenerativeQuestionConfig: """Post-rpc interceptor for update_generative_question_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_question_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_question_config` interceptor runs + before the `post_update_generative_question_config_with_metadata` interceptor. """ return response + def post_update_generative_question_config_with_metadata( + self, + response: generative_question.GenerativeQuestionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_question_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_question_config_with_metadata` + interceptor in new development instead of the `post_update_generative_question_config` interceptor. + When both interceptors are used, this `post_update_generative_question_config_with_metadata` interceptor runs after the + `post_update_generative_question_config` interceptor. The (possibly modified) response returned by + `post_update_generative_question_config` will be passed to + `post_update_generative_question_config_with_metadata`. + """ + return response, metadata + def pre_update_generative_questions_feature_config( self, request: generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest, @@ -245,12 +349,38 @@ def post_update_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for update_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_questions_feature_config` interceptor runs + before the `post_update_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_update_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_update_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_update_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_update_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_update_generative_questions_feature_config` will be passed to + `post_update_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -531,6 +661,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_update_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_batch_update_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -686,6 +823,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_generative_questions_feature_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -840,6 +984,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -997,6 +1148,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_generative_question_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_question_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1160,6 +1318,13 @@ def __call__( resp = self._interceptor.post_update_generative_questions_feature_config( resp ) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/client.py index 9b65fbbaa00f..c29407b97b5f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -528,6 +530,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1709,16 +1738,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1764,16 +1797,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/transports/rest.py index 6317dee1177c..edad856543ab 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/model_service/transports/rest.py @@ -158,12 +158,35 @@ def post_create_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_create_model` interceptor runs + before the `post_create_model_with_metadata` interceptor. """ return response + def post_create_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_create_model_with_metadata` + interceptor in new development instead of the `post_create_model` interceptor. + When both interceptors are used, this `post_create_model_with_metadata` interceptor runs after the + `post_create_model` interceptor. The (possibly modified) response returned by + `post_create_model` will be passed to + `post_create_model_with_metadata`. + """ + return response, metadata + def pre_delete_model( self, request: model_service.DeleteModelRequest, @@ -193,12 +216,33 @@ def pre_get_model( def post_get_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for get_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_get_model` interceptor runs + before the `post_get_model_with_metadata` interceptor. """ return response + def post_get_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_get_model_with_metadata` + interceptor in new development instead of the `post_get_model` interceptor. + When both interceptors are used, this `post_get_model_with_metadata` interceptor runs after the + `post_get_model` interceptor. The (possibly modified) response returned by + `post_get_model` will be passed to + `post_get_model_with_metadata`. + """ + return response, metadata + def pre_list_models( self, request: model_service.ListModelsRequest, @@ -218,12 +262,37 @@ def post_list_models( ) -> model_service.ListModelsResponse: """Post-rpc interceptor for list_models - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_models_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_list_models` interceptor runs + before the `post_list_models_with_metadata` interceptor. """ return response + def post_list_models_with_metadata( + self, + response: model_service.ListModelsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + model_service.ListModelsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_models + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_list_models_with_metadata` + interceptor in new development instead of the `post_list_models` interceptor. + When both interceptors are used, this `post_list_models_with_metadata` interceptor runs after the + `post_list_models` interceptor. The (possibly modified) response returned by + `post_list_models` will be passed to + `post_list_models_with_metadata`. + """ + return response, metadata + def pre_pause_model( self, request: model_service.PauseModelRequest, @@ -241,12 +310,33 @@ def pre_pause_model( def post_pause_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for pause_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_pause_model` interceptor runs + before the `post_pause_model_with_metadata` interceptor. """ return response + def post_pause_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_pause_model_with_metadata` + interceptor in new development instead of the `post_pause_model` interceptor. + When both interceptors are used, this `post_pause_model_with_metadata` interceptor runs after the + `post_pause_model` interceptor. The (possibly modified) response returned by + `post_pause_model` will be passed to + `post_pause_model_with_metadata`. + """ + return response, metadata + def pre_resume_model( self, request: model_service.ResumeModelRequest, @@ -264,12 +354,33 @@ def pre_resume_model( def post_resume_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for resume_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_resume_model` interceptor runs + before the `post_resume_model_with_metadata` interceptor. """ return response + def post_resume_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_resume_model_with_metadata` + interceptor in new development instead of the `post_resume_model` interceptor. + When both interceptors are used, this `post_resume_model_with_metadata` interceptor runs after the + `post_resume_model` interceptor. The (possibly modified) response returned by + `post_resume_model` will be passed to + `post_resume_model_with_metadata`. + """ + return response, metadata + def pre_tune_model( self, request: model_service.TuneModelRequest, @@ -287,12 +398,35 @@ def post_tune_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for tune_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_tune_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_tune_model` interceptor runs + before the `post_tune_model_with_metadata` interceptor. """ return response + def post_tune_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for tune_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_tune_model_with_metadata` + interceptor in new development instead of the `post_tune_model` interceptor. + When both interceptors are used, this `post_tune_model_with_metadata` interceptor runs after the + `post_tune_model` interceptor. The (possibly modified) response returned by + `post_tune_model` will be passed to + `post_tune_model_with_metadata`. + """ + return response, metadata + def pre_update_model( self, request: model_service.UpdateModelRequest, @@ -310,12 +444,35 @@ def pre_update_model( def post_update_model(self, response: gcr_model.Model) -> gcr_model.Model: """Post-rpc interceptor for update_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_update_model` interceptor runs + before the `post_update_model_with_metadata` interceptor. """ return response + def post_update_model_with_metadata( + self, + response: gcr_model.Model, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_update_model_with_metadata` + interceptor in new development instead of the `post_update_model` interceptor. + When both interceptors are used, this `post_update_model_with_metadata` interceptor runs after the + `post_update_model` interceptor. The (possibly modified) response returned by + `post_update_model` will be passed to + `post_update_model_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -655,6 +812,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -913,6 +1074,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1058,6 +1223,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_models(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_models_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1219,6 +1388,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1378,6 +1551,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1532,6 +1709,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_tune_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_tune_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1691,6 +1872,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/client.py index 4983d8ec1e2d..af45f06ce72c 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/transports/rest.py index 250c4afedc33..142d78d0e6c4 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/prediction_service/transports/rest.py @@ -103,12 +103,37 @@ def post_predict( ) -> prediction_service.PredictResponse: """Post-rpc interceptor for predict - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_predict_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionService server but before - it is returned to user code. + it is returned to user code. This `post_predict` interceptor runs + before the `post_predict_with_metadata` interceptor. """ return response + def post_predict_with_metadata( + self, + response: prediction_service.PredictResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_service.PredictResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for predict + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionService server but before it is returned to user code. + + We recommend only using this `post_predict_with_metadata` + interceptor in new development instead of the `post_predict` interceptor. + When both interceptors are used, this `post_predict_with_metadata` interceptor runs after the + `post_predict` interceptor. The (possibly modified) response returned by + `post_predict` will be passed to + `post_predict_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -373,6 +398,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_predict(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_predict_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/client.py index 51e2d412cc76..8ab2f758cfbf 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -526,6 +528,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2574,16 +2603,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2629,16 +2662,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/transports/rest.py index 470745be7bb0..97949b546bc7 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/product_service/transports/rest.py @@ -192,12 +192,35 @@ def post_add_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_fulfillment_places` interceptor runs + before the `post_add_fulfillment_places_with_metadata` interceptor. """ return response + def post_add_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_add_fulfillment_places` interceptor. + When both interceptors are used, this `post_add_fulfillment_places_with_metadata` interceptor runs after the + `post_add_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_add_fulfillment_places` will be passed to + `post_add_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_add_local_inventories( self, request: product_service.AddLocalInventoriesRequest, @@ -218,12 +241,35 @@ def post_add_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_local_inventories` interceptor runs + before the `post_add_local_inventories_with_metadata` interceptor. """ return response + def post_add_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_local_inventories_with_metadata` + interceptor in new development instead of the `post_add_local_inventories` interceptor. + When both interceptors are used, this `post_add_local_inventories_with_metadata` interceptor runs after the + `post_add_local_inventories` interceptor. The (possibly modified) response returned by + `post_add_local_inventories` will be passed to + `post_add_local_inventories_with_metadata`. + """ + return response, metadata + def pre_create_product( self, request: product_service.CreateProductRequest, @@ -241,12 +287,35 @@ def pre_create_product( def post_create_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for create_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_create_product` interceptor runs + before the `post_create_product_with_metadata` interceptor. """ return response + def post_create_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_create_product_with_metadata` + interceptor in new development instead of the `post_create_product` interceptor. + When both interceptors are used, this `post_create_product_with_metadata` interceptor runs after the + `post_create_product` interceptor. The (possibly modified) response returned by + `post_create_product` will be passed to + `post_create_product_with_metadata`. + """ + return response, metadata + def pre_delete_product( self, request: product_service.DeleteProductRequest, @@ -278,12 +347,35 @@ def pre_get_product( def post_get_product(self, response: product.Product) -> product.Product: """Post-rpc interceptor for get_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_get_product` interceptor runs + before the `post_get_product_with_metadata` interceptor. """ return response + def post_get_product_with_metadata( + self, + response: product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_get_product_with_metadata` + interceptor in new development instead of the `post_get_product` interceptor. + When both interceptors are used, this `post_get_product_with_metadata` interceptor runs after the + `post_get_product` interceptor. The (possibly modified) response returned by + `post_get_product` will be passed to + `post_get_product_with_metadata`. + """ + return response, metadata + def pre_import_products( self, request: import_config.ImportProductsRequest, @@ -303,12 +395,35 @@ def post_import_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_import_products` interceptor runs + before the `post_import_products_with_metadata` interceptor. """ return response + def post_import_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_import_products_with_metadata` + interceptor in new development instead of the `post_import_products` interceptor. + When both interceptors are used, this `post_import_products_with_metadata` interceptor runs after the + `post_import_products` interceptor. The (possibly modified) response returned by + `post_import_products` will be passed to + `post_import_products_with_metadata`. + """ + return response, metadata + def pre_list_products( self, request: product_service.ListProductsRequest, @@ -328,12 +443,37 @@ def post_list_products( ) -> product_service.ListProductsResponse: """Post-rpc interceptor for list_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_list_products` interceptor runs + before the `post_list_products_with_metadata` interceptor. """ return response + def post_list_products_with_metadata( + self, + response: product_service.ListProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + product_service.ListProductsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_list_products_with_metadata` + interceptor in new development instead of the `post_list_products` interceptor. + When both interceptors are used, this `post_list_products_with_metadata` interceptor runs after the + `post_list_products` interceptor. The (possibly modified) response returned by + `post_list_products` will be passed to + `post_list_products_with_metadata`. + """ + return response, metadata + def pre_purge_products( self, request: purge_config.PurgeProductsRequest, @@ -353,12 +493,35 @@ def post_purge_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_purge_products` interceptor runs + before the `post_purge_products_with_metadata` interceptor. """ return response + def post_purge_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_purge_products_with_metadata` + interceptor in new development instead of the `post_purge_products` interceptor. + When both interceptors are used, this `post_purge_products_with_metadata` interceptor runs after the + `post_purge_products` interceptor. The (possibly modified) response returned by + `post_purge_products` will be passed to + `post_purge_products_with_metadata`. + """ + return response, metadata + def pre_remove_fulfillment_places( self, request: product_service.RemoveFulfillmentPlacesRequest, @@ -379,12 +542,35 @@ def post_remove_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_fulfillment_places` interceptor runs + before the `post_remove_fulfillment_places_with_metadata` interceptor. """ return response + def post_remove_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_remove_fulfillment_places` interceptor. + When both interceptors are used, this `post_remove_fulfillment_places_with_metadata` interceptor runs after the + `post_remove_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_remove_fulfillment_places` will be passed to + `post_remove_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_remove_local_inventories( self, request: product_service.RemoveLocalInventoriesRequest, @@ -405,12 +591,35 @@ def post_remove_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_local_inventories` interceptor runs + before the `post_remove_local_inventories_with_metadata` interceptor. """ return response + def post_remove_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_local_inventories_with_metadata` + interceptor in new development instead of the `post_remove_local_inventories` interceptor. + When both interceptors are used, this `post_remove_local_inventories_with_metadata` interceptor runs after the + `post_remove_local_inventories` interceptor. The (possibly modified) response returned by + `post_remove_local_inventories` will be passed to + `post_remove_local_inventories_with_metadata`. + """ + return response, metadata + def pre_set_inventory( self, request: product_service.SetInventoryRequest, @@ -430,12 +639,35 @@ def post_set_inventory( ) -> operations_pb2.Operation: """Post-rpc interceptor for set_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_set_inventory` interceptor runs + before the `post_set_inventory_with_metadata` interceptor. """ return response + def post_set_inventory_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_set_inventory_with_metadata` + interceptor in new development instead of the `post_set_inventory` interceptor. + When both interceptors are used, this `post_set_inventory_with_metadata` interceptor runs after the + `post_set_inventory` interceptor. The (possibly modified) response returned by + `post_set_inventory` will be passed to + `post_set_inventory_with_metadata`. + """ + return response, metadata + def pre_update_product( self, request: product_service.UpdateProductRequest, @@ -453,12 +685,35 @@ def pre_update_product( def post_update_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for update_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_update_product` interceptor runs + before the `post_update_product_with_metadata` interceptor. """ return response + def post_update_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_update_product_with_metadata` + interceptor in new development instead of the `post_update_product` interceptor. + When both interceptors are used, this `post_update_product_with_metadata` interceptor runs after the + `post_update_product` interceptor. The (possibly modified) response returned by + `post_update_product` will be passed to + `post_update_product_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -787,6 +1042,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -939,6 +1198,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1090,6 +1353,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1345,6 +1612,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1492,6 +1763,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1637,6 +1912,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1787,6 +2066,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1941,6 +2224,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2095,6 +2382,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2244,6 +2535,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2395,6 +2690,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/client.py index 9a19247a91bd..113d6a1889e4 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -566,6 +568,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -927,16 +956,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -982,16 +1015,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/transports/rest.py index 9a7b6575ca30..61be6d26daf1 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/search_service/transports/rest.py @@ -101,12 +101,35 @@ def post_search( ) -> search_service.SearchResponse: """Post-rpc interceptor for search - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the SearchService server but before - it is returned to user code. + it is returned to user code. This `post_search` interceptor runs + before the `post_search_with_metadata` interceptor. """ return response + def post_search_with_metadata( + self, + response: search_service.SearchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[search_service.SearchResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for search + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the SearchService server but before it is returned to user code. + + We recommend only using this `post_search_with_metadata` + interceptor in new development instead of the `post_search` interceptor. + When both interceptors are used, this `post_search_with_metadata` interceptor runs after the + `post_search` interceptor. The (possibly modified) response returned by + `post_search` will be passed to + `post_search_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -378,6 +401,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/client.py index 042cc00f555f..6e55a6db4f01 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1610,16 +1639,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1665,16 +1698,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/transports/rest.py index b649454968b0..b830b090a54d 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/serving_config_service/transports/rest.py @@ -151,12 +151,37 @@ def post_add_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for add_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_add_control` interceptor runs + before the `post_add_control_with_metadata` interceptor. """ return response + def post_add_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for add_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_add_control_with_metadata` + interceptor in new development instead of the `post_add_control` interceptor. + When both interceptors are used, this `post_add_control_with_metadata` interceptor runs after the + `post_add_control` interceptor. The (possibly modified) response returned by + `post_add_control` will be passed to + `post_add_control_with_metadata`. + """ + return response, metadata + def pre_create_serving_config( self, request: serving_config_service.CreateServingConfigRequest, @@ -177,12 +202,37 @@ def post_create_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for create_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_create_serving_config` interceptor runs + before the `post_create_serving_config_with_metadata` interceptor. """ return response + def post_create_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for create_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_create_serving_config_with_metadata` + interceptor in new development instead of the `post_create_serving_config` interceptor. + When both interceptors are used, this `post_create_serving_config_with_metadata` interceptor runs after the + `post_create_serving_config` interceptor. The (possibly modified) response returned by + `post_create_serving_config` will be passed to + `post_create_serving_config_with_metadata`. + """ + return response, metadata + def pre_delete_serving_config( self, request: serving_config_service.DeleteServingConfigRequest, @@ -218,12 +268,35 @@ def post_get_serving_config( ) -> serving_config.ServingConfig: """Post-rpc interceptor for get_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_get_serving_config` interceptor runs + before the `post_get_serving_config_with_metadata` interceptor. """ return response + def post_get_serving_config_with_metadata( + self, + response: serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_get_serving_config_with_metadata` + interceptor in new development instead of the `post_get_serving_config` interceptor. + When both interceptors are used, this `post_get_serving_config_with_metadata` interceptor runs after the + `post_get_serving_config` interceptor. The (possibly modified) response returned by + `post_get_serving_config` will be passed to + `post_get_serving_config_with_metadata`. + """ + return response, metadata + def pre_list_serving_configs( self, request: serving_config_service.ListServingConfigsRequest, @@ -244,12 +317,38 @@ def post_list_serving_configs( ) -> serving_config_service.ListServingConfigsResponse: """Post-rpc interceptor for list_serving_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_serving_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_list_serving_configs` interceptor runs + before the `post_list_serving_configs_with_metadata` interceptor. """ return response + def post_list_serving_configs_with_metadata( + self, + response: serving_config_service.ListServingConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + serving_config_service.ListServingConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_serving_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_list_serving_configs_with_metadata` + interceptor in new development instead of the `post_list_serving_configs` interceptor. + When both interceptors are used, this `post_list_serving_configs_with_metadata` interceptor runs after the + `post_list_serving_configs` interceptor. The (possibly modified) response returned by + `post_list_serving_configs` will be passed to + `post_list_serving_configs_with_metadata`. + """ + return response, metadata + def pre_remove_control( self, request: serving_config_service.RemoveControlRequest, @@ -270,12 +369,37 @@ def post_remove_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for remove_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_remove_control` interceptor runs + before the `post_remove_control_with_metadata` interceptor. """ return response + def post_remove_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for remove_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_remove_control_with_metadata` + interceptor in new development instead of the `post_remove_control` interceptor. + When both interceptors are used, this `post_remove_control_with_metadata` interceptor runs after the + `post_remove_control` interceptor. The (possibly modified) response returned by + `post_remove_control` will be passed to + `post_remove_control_with_metadata`. + """ + return response, metadata + def pre_update_serving_config( self, request: serving_config_service.UpdateServingConfigRequest, @@ -296,12 +420,37 @@ def post_update_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for update_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_update_serving_config` interceptor runs + before the `post_update_serving_config_with_metadata` interceptor. """ return response + def post_update_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_update_serving_config_with_metadata` + interceptor in new development instead of the `post_update_serving_config` interceptor. + When both interceptors are used, this `post_update_serving_config_with_metadata` interceptor runs after the + `post_update_serving_config` interceptor. The (possibly modified) response returned by + `post_update_serving_config` will be passed to + `post_update_serving_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -567,6 +716,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -725,6 +878,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -988,6 +1145,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1136,6 +1297,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_serving_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_serving_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1291,6 +1456,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1449,6 +1618,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/client.py index c0b09ef6c4ae..06ee2f78da16 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -525,6 +527,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1337,16 +1366,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1392,16 +1425,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/transports/rest.py index 7d43276f9ca6..a071f2a1b616 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/services/user_event_service/transports/rest.py @@ -142,12 +142,35 @@ def post_collect_user_event( ) -> httpbody_pb2.HttpBody: """Post-rpc interceptor for collect_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_collect_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_collect_user_event` interceptor runs + before the `post_collect_user_event_with_metadata` interceptor. """ return response + def post_collect_user_event_with_metadata( + self, + response: httpbody_pb2.HttpBody, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[httpbody_pb2.HttpBody, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for collect_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_collect_user_event_with_metadata` + interceptor in new development instead of the `post_collect_user_event` interceptor. + When both interceptors are used, this `post_collect_user_event_with_metadata` interceptor runs after the + `post_collect_user_event` interceptor. The (possibly modified) response returned by + `post_collect_user_event` will be passed to + `post_collect_user_event_with_metadata`. + """ + return response, metadata + def pre_import_user_events( self, request: import_config.ImportUserEventsRequest, @@ -167,12 +190,35 @@ def post_import_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_import_user_events` interceptor runs + before the `post_import_user_events_with_metadata` interceptor. """ return response + def post_import_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_import_user_events_with_metadata` + interceptor in new development instead of the `post_import_user_events` interceptor. + When both interceptors are used, this `post_import_user_events_with_metadata` interceptor runs after the + `post_import_user_events` interceptor. The (possibly modified) response returned by + `post_import_user_events` will be passed to + `post_import_user_events_with_metadata`. + """ + return response, metadata + def pre_purge_user_events( self, request: purge_config.PurgeUserEventsRequest, @@ -192,12 +238,35 @@ def post_purge_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_purge_user_events` interceptor runs + before the `post_purge_user_events_with_metadata` interceptor. """ return response + def post_purge_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_purge_user_events_with_metadata` + interceptor in new development instead of the `post_purge_user_events` interceptor. + When both interceptors are used, this `post_purge_user_events_with_metadata` interceptor runs after the + `post_purge_user_events` interceptor. The (possibly modified) response returned by + `post_purge_user_events` will be passed to + `post_purge_user_events_with_metadata`. + """ + return response, metadata + def pre_rejoin_user_events( self, request: user_event_service.RejoinUserEventsRequest, @@ -218,12 +287,35 @@ def post_rejoin_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for rejoin_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_rejoin_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_rejoin_user_events` interceptor runs + before the `post_rejoin_user_events_with_metadata` interceptor. """ return response + def post_rejoin_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for rejoin_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_rejoin_user_events_with_metadata` + interceptor in new development instead of the `post_rejoin_user_events` interceptor. + When both interceptors are used, this `post_rejoin_user_events_with_metadata` interceptor runs after the + `post_rejoin_user_events` interceptor. The (possibly modified) response returned by + `post_rejoin_user_events` will be passed to + `post_rejoin_user_events_with_metadata`. + """ + return response, metadata + def pre_write_user_event( self, request: user_event_service.WriteUserEventRequest, @@ -244,12 +336,35 @@ def post_write_user_event( ) -> user_event.UserEvent: """Post-rpc interceptor for write_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_write_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_write_user_event` interceptor runs + before the `post_write_user_event_with_metadata` interceptor. """ return response + def post_write_user_event_with_metadata( + self, + response: user_event.UserEvent, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[user_event.UserEvent, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for write_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_write_user_event_with_metadata` + interceptor in new development instead of the `post_write_user_event` interceptor. + When both interceptors are used, this `post_write_user_event_with_metadata` interceptor runs after the + `post_write_user_event` interceptor. The (possibly modified) response returned by + `post_write_user_event` will be passed to + `post_write_user_event_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -619,6 +734,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_collect_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_collect_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -770,6 +889,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -921,6 +1044,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1072,6 +1199,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_rejoin_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_rejoin_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1225,6 +1356,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_write_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_write_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py index 45f4e360312c..558c8aab67c5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.24.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/client.py index ad57e899870f..f3180aa685c7 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -469,6 +471,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/transports/rest.py index 0012225008d2..f453355d979e 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/analytics_service/transports/rest.py @@ -104,12 +104,35 @@ def post_export_analytics_metrics( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_analytics_metrics - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_analytics_metrics_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AnalyticsService server but before - it is returned to user code. + it is returned to user code. This `post_export_analytics_metrics` interceptor runs + before the `post_export_analytics_metrics_with_metadata` interceptor. """ return response + def post_export_analytics_metrics_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_analytics_metrics + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AnalyticsService server but before it is returned to user code. + + We recommend only using this `post_export_analytics_metrics_with_metadata` + interceptor in new development instead of the `post_export_analytics_metrics` interceptor. + When both interceptors are used, this `post_export_analytics_metrics_with_metadata` interceptor runs after the + `post_export_analytics_metrics` interceptor. The (possibly modified) response returned by + `post_export_analytics_metrics` will be passed to + `post_export_analytics_metrics_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -444,6 +467,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_analytics_metrics(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_analytics_metrics_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/client.py index 915a4be3e171..a1695e9cb8c3 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -542,6 +544,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1014,16 +1043,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1069,16 +1102,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/transports/rest.py index b66c1fa163f6..e18c2f1b9d7f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/branch_service/transports/rest.py @@ -109,12 +109,33 @@ def pre_get_branch( def post_get_branch(self, response: branch.Branch) -> branch.Branch: """Post-rpc interceptor for get_branch - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_branch_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BranchService server but before - it is returned to user code. + it is returned to user code. This `post_get_branch` interceptor runs + before the `post_get_branch_with_metadata` interceptor. """ return response + def post_get_branch_with_metadata( + self, response: branch.Branch, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[branch.Branch, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_branch + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BranchService server but before it is returned to user code. + + We recommend only using this `post_get_branch_with_metadata` + interceptor in new development instead of the `post_get_branch` interceptor. + When both interceptors are used, this `post_get_branch_with_metadata` interceptor runs after the + `post_get_branch` interceptor. The (possibly modified) response returned by + `post_get_branch` will be passed to + `post_get_branch_with_metadata`. + """ + return response, metadata + def pre_list_branches( self, request: branch_service.ListBranchesRequest, @@ -134,12 +155,37 @@ def post_list_branches( ) -> branch_service.ListBranchesResponse: """Post-rpc interceptor for list_branches - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_branches_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the BranchService server but before - it is returned to user code. + it is returned to user code. This `post_list_branches` interceptor runs + before the `post_list_branches_with_metadata` interceptor. """ return response + def post_list_branches_with_metadata( + self, + response: branch_service.ListBranchesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + branch_service.ListBranchesResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_branches + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the BranchService server but before it is returned to user code. + + We recommend only using this `post_list_branches_with_metadata` + interceptor in new development instead of the `post_list_branches` interceptor. + When both interceptors are used, this `post_list_branches_with_metadata` interceptor runs after the + `post_list_branches` interceptor. The (possibly modified) response returned by + `post_list_branches` will be passed to + `post_list_branches_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -408,6 +454,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_branch(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_branch_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -553,6 +603,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_branches(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_branches_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/client.py index 23272b63c370..e97865724d63 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -559,6 +561,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2191,16 +2220,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2246,16 +2279,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/transports/rest.py index f423b8de1495..b86871535a02 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/catalog_service/transports/rest.py @@ -191,12 +191,35 @@ def post_add_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for add_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_add_catalog_attribute` interceptor runs + before the `post_add_catalog_attribute_with_metadata` interceptor. """ return response + def post_add_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_add_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_add_catalog_attribute` interceptor. + When both interceptors are used, this `post_add_catalog_attribute_with_metadata` interceptor runs after the + `post_add_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_add_catalog_attribute` will be passed to + `post_add_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_batch_remove_catalog_attributes( self, request: catalog_service.BatchRemoveCatalogAttributesRequest, @@ -217,12 +240,38 @@ def post_batch_remove_catalog_attributes( ) -> catalog_service.BatchRemoveCatalogAttributesResponse: """Post-rpc interceptor for batch_remove_catalog_attributes - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_remove_catalog_attributes_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_batch_remove_catalog_attributes` interceptor runs + before the `post_batch_remove_catalog_attributes_with_metadata` interceptor. """ return response + def post_batch_remove_catalog_attributes_with_metadata( + self, + response: catalog_service.BatchRemoveCatalogAttributesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.BatchRemoveCatalogAttributesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for batch_remove_catalog_attributes + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_batch_remove_catalog_attributes_with_metadata` + interceptor in new development instead of the `post_batch_remove_catalog_attributes` interceptor. + When both interceptors are used, this `post_batch_remove_catalog_attributes_with_metadata` interceptor runs after the + `post_batch_remove_catalog_attributes` interceptor. The (possibly modified) response returned by + `post_batch_remove_catalog_attributes` will be passed to + `post_batch_remove_catalog_attributes_with_metadata`. + """ + return response, metadata + def pre_get_attributes_config( self, request: catalog_service.GetAttributesConfigRequest, @@ -243,12 +292,35 @@ def post_get_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for get_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_attributes_config` interceptor runs + before the `post_get_attributes_config_with_metadata` interceptor. """ return response + def post_get_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_attributes_config_with_metadata` + interceptor in new development instead of the `post_get_attributes_config` interceptor. + When both interceptors are used, this `post_get_attributes_config_with_metadata` interceptor runs after the + `post_get_attributes_config` interceptor. The (possibly modified) response returned by + `post_get_attributes_config` will be passed to + `post_get_attributes_config_with_metadata`. + """ + return response, metadata + def pre_get_completion_config( self, request: catalog_service.GetCompletionConfigRequest, @@ -269,12 +341,35 @@ def post_get_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for get_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_completion_config` interceptor runs + before the `post_get_completion_config_with_metadata` interceptor. """ return response + def post_get_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_completion_config_with_metadata` + interceptor in new development instead of the `post_get_completion_config` interceptor. + When both interceptors are used, this `post_get_completion_config_with_metadata` interceptor runs after the + `post_get_completion_config` interceptor. The (possibly modified) response returned by + `post_get_completion_config` will be passed to + `post_get_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_default_branch( self, request: catalog_service.GetDefaultBranchRequest, @@ -294,12 +389,38 @@ def post_get_default_branch( ) -> catalog_service.GetDefaultBranchResponse: """Post-rpc interceptor for get_default_branch - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_default_branch_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_default_branch` interceptor runs + before the `post_get_default_branch_with_metadata` interceptor. """ return response + def post_get_default_branch_with_metadata( + self, + response: catalog_service.GetDefaultBranchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.GetDefaultBranchResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_default_branch + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_default_branch_with_metadata` + interceptor in new development instead of the `post_get_default_branch` interceptor. + When both interceptors are used, this `post_get_default_branch_with_metadata` interceptor runs after the + `post_get_default_branch` interceptor. The (possibly modified) response returned by + `post_get_default_branch` will be passed to + `post_get_default_branch_with_metadata`. + """ + return response, metadata + def pre_list_catalogs( self, request: catalog_service.ListCatalogsRequest, @@ -319,12 +440,37 @@ def post_list_catalogs( ) -> catalog_service.ListCatalogsResponse: """Post-rpc interceptor for list_catalogs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_catalogs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_list_catalogs` interceptor runs + before the `post_list_catalogs_with_metadata` interceptor. """ return response + def post_list_catalogs_with_metadata( + self, + response: catalog_service.ListCatalogsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.ListCatalogsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_catalogs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_list_catalogs_with_metadata` + interceptor in new development instead of the `post_list_catalogs` interceptor. + When both interceptors are used, this `post_list_catalogs_with_metadata` interceptor runs after the + `post_list_catalogs` interceptor. The (possibly modified) response returned by + `post_list_catalogs` will be passed to + `post_list_catalogs_with_metadata`. + """ + return response, metadata + def pre_remove_catalog_attribute( self, request: catalog_service.RemoveCatalogAttributeRequest, @@ -345,12 +491,35 @@ def post_remove_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for remove_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_remove_catalog_attribute` interceptor runs + before the `post_remove_catalog_attribute_with_metadata` interceptor. """ return response + def post_remove_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_remove_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_remove_catalog_attribute` interceptor. + When both interceptors are used, this `post_remove_catalog_attribute_with_metadata` interceptor runs after the + `post_remove_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_remove_catalog_attribute` will be passed to + `post_remove_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_replace_catalog_attribute( self, request: catalog_service.ReplaceCatalogAttributeRequest, @@ -371,12 +540,35 @@ def post_replace_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for replace_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_replace_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_replace_catalog_attribute` interceptor runs + before the `post_replace_catalog_attribute_with_metadata` interceptor. """ return response + def post_replace_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for replace_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_replace_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_replace_catalog_attribute` interceptor. + When both interceptors are used, this `post_replace_catalog_attribute_with_metadata` interceptor runs after the + `post_replace_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_replace_catalog_attribute` will be passed to + `post_replace_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_set_default_branch( self, request: catalog_service.SetDefaultBranchRequest, @@ -411,12 +603,35 @@ def post_update_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for update_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_attributes_config` interceptor runs + before the `post_update_attributes_config_with_metadata` interceptor. """ return response + def post_update_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_attributes_config_with_metadata` + interceptor in new development instead of the `post_update_attributes_config` interceptor. + When both interceptors are used, this `post_update_attributes_config_with_metadata` interceptor runs after the + `post_update_attributes_config` interceptor. The (possibly modified) response returned by + `post_update_attributes_config` will be passed to + `post_update_attributes_config_with_metadata`. + """ + return response, metadata + def pre_update_catalog( self, request: catalog_service.UpdateCatalogRequest, @@ -434,12 +649,35 @@ def pre_update_catalog( def post_update_catalog(self, response: gcr_catalog.Catalog) -> gcr_catalog.Catalog: """Post-rpc interceptor for update_catalog - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_catalog_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_catalog` interceptor runs + before the `post_update_catalog_with_metadata` interceptor. """ return response + def post_update_catalog_with_metadata( + self, + response: gcr_catalog.Catalog, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_catalog.Catalog, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_catalog + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_catalog_with_metadata` + interceptor in new development instead of the `post_update_catalog` interceptor. + When both interceptors are used, this `post_update_catalog_with_metadata` interceptor runs after the + `post_update_catalog` interceptor. The (possibly modified) response returned by + `post_update_catalog` will be passed to + `post_update_catalog_with_metadata`. + """ + return response, metadata + def pre_update_completion_config( self, request: catalog_service.UpdateCompletionConfigRequest, @@ -460,12 +698,35 @@ def post_update_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for update_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_completion_config` interceptor runs + before the `post_update_completion_config_with_metadata` interceptor. """ return response + def post_update_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_completion_config_with_metadata` + interceptor in new development instead of the `post_update_completion_config` interceptor. + When both interceptors are used, this `post_update_completion_config_with_metadata` interceptor runs after the + `post_update_completion_config` interceptor. The (possibly modified) response returned by + `post_update_completion_config` will be passed to + `post_update_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -731,6 +992,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -887,6 +1152,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_remove_catalog_attributes(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_batch_remove_catalog_attributes_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1036,6 +1308,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1184,6 +1460,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1329,6 +1609,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_default_branch(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_default_branch_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1476,6 +1760,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_catalogs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_catalogs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1631,6 +1919,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1784,6 +2076,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_replace_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_replace_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2052,6 +2348,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2200,6 +2500,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_catalog(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_catalog_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2356,6 +2660,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/client.py index d8082e6699b6..c9bc25c2281b 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -493,6 +495,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -957,16 +986,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1012,16 +1045,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/transports/rest.py index dfdabead1caf..54a9a7d63a8c 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/completion_service/transports/rest.py @@ -111,12 +111,38 @@ def post_complete_query( ) -> completion_service.CompleteQueryResponse: """Post-rpc interceptor for complete_query - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_complete_query_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_complete_query` interceptor runs + before the `post_complete_query_with_metadata` interceptor. """ return response + def post_complete_query_with_metadata( + self, + response: completion_service.CompleteQueryResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + completion_service.CompleteQueryResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for complete_query + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_complete_query_with_metadata` + interceptor in new development instead of the `post_complete_query` interceptor. + When both interceptors are used, this `post_complete_query_with_metadata` interceptor runs after the + `post_complete_query` interceptor. The (possibly modified) response returned by + `post_complete_query` will be passed to + `post_complete_query_with_metadata`. + """ + return response, metadata + def pre_import_completion_data( self, request: import_config.ImportCompletionDataRequest, @@ -137,12 +163,35 @@ def post_import_completion_data( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_completion_data - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_completion_data_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_import_completion_data` interceptor runs + before the `post_import_completion_data_with_metadata` interceptor. """ return response + def post_import_completion_data_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_completion_data + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_import_completion_data_with_metadata` + interceptor in new development instead of the `post_import_completion_data` interceptor. + When both interceptors are used, this `post_import_completion_data_with_metadata` interceptor runs after the + `post_import_completion_data` interceptor. The (possibly modified) response returned by + `post_import_completion_data` will be passed to + `post_import_completion_data_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -467,6 +516,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_complete_query(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_complete_query_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -622,6 +675,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_completion_data(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_completion_data_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/client.py index 852f59054240..2d3d970d9cd5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1360,16 +1389,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1415,16 +1448,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/transports/rest.py index 2e9decfc8e7d..849a6ed1580a 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/control_service/transports/rest.py @@ -132,12 +132,35 @@ def pre_create_control( def post_create_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for create_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_create_control` interceptor runs + before the `post_create_control_with_metadata` interceptor. """ return response + def post_create_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_create_control_with_metadata` + interceptor in new development instead of the `post_create_control` interceptor. + When both interceptors are used, this `post_create_control_with_metadata` interceptor runs after the + `post_create_control` interceptor. The (possibly modified) response returned by + `post_create_control` will be passed to + `post_create_control_with_metadata`. + """ + return response, metadata + def pre_delete_control( self, request: control_service.DeleteControlRequest, @@ -169,12 +192,35 @@ def pre_get_control( def post_get_control(self, response: control.Control) -> control.Control: """Post-rpc interceptor for get_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_get_control` interceptor runs + before the `post_get_control_with_metadata` interceptor. """ return response + def post_get_control_with_metadata( + self, + response: control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_get_control_with_metadata` + interceptor in new development instead of the `post_get_control` interceptor. + When both interceptors are used, this `post_get_control_with_metadata` interceptor runs after the + `post_get_control` interceptor. The (possibly modified) response returned by + `post_get_control` will be passed to + `post_get_control_with_metadata`. + """ + return response, metadata + def pre_list_controls( self, request: control_service.ListControlsRequest, @@ -194,12 +240,37 @@ def post_list_controls( ) -> control_service.ListControlsResponse: """Post-rpc interceptor for list_controls - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_controls_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_list_controls` interceptor runs + before the `post_list_controls_with_metadata` interceptor. """ return response + def post_list_controls_with_metadata( + self, + response: control_service.ListControlsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + control_service.ListControlsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_controls + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_list_controls_with_metadata` + interceptor in new development instead of the `post_list_controls` interceptor. + When both interceptors are used, this `post_list_controls_with_metadata` interceptor runs after the + `post_list_controls` interceptor. The (possibly modified) response returned by + `post_list_controls` will be passed to + `post_list_controls_with_metadata`. + """ + return response, metadata + def pre_update_control( self, request: control_service.UpdateControlRequest, @@ -217,12 +288,35 @@ def pre_update_control( def post_update_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for update_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_update_control` interceptor runs + before the `post_update_control_with_metadata` interceptor. """ return response + def post_update_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_update_control_with_metadata` + interceptor in new development instead of the `post_update_control` interceptor. + When both interceptors are used, this `post_update_control_with_metadata` interceptor runs after the + `post_update_control` interceptor. The (possibly modified) response returned by + `post_update_control` will be passed to + `post_update_control_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -487,6 +581,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -739,6 +837,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -879,6 +981,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_controls(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_controls_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1031,6 +1137,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/client.py index 27e23f2b0553..2103a14cc343 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -494,6 +496,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1414,16 +1443,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1469,16 +1502,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/transports/rest.py index f094e752e2ba..65f42f7f3370 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/generative_question_service/transports/rest.py @@ -140,12 +140,38 @@ def post_batch_update_generative_question_configs( ) -> generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse: """Post-rpc interceptor for batch_update_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_update_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_batch_update_generative_question_configs` interceptor runs + before the `post_batch_update_generative_question_configs_with_metadata` interceptor. """ return response + def post_batch_update_generative_question_configs_with_metadata( + self, + response: generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for batch_update_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_batch_update_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_batch_update_generative_question_configs` interceptor. + When both interceptors are used, this `post_batch_update_generative_question_configs_with_metadata` interceptor runs after the + `post_batch_update_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_batch_update_generative_question_configs` will be passed to + `post_batch_update_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_get_generative_questions_feature_config( self, request: generative_question_service.GetGenerativeQuestionsFeatureConfigRequest, @@ -166,12 +192,38 @@ def post_get_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for get_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_get_generative_questions_feature_config` interceptor runs + before the `post_get_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_get_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_get_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_get_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_get_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_get_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_get_generative_questions_feature_config` will be passed to + `post_get_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_list_generative_question_configs( self, request: generative_question_service.ListGenerativeQuestionConfigsRequest, @@ -193,12 +245,38 @@ def post_list_generative_question_configs( ) -> generative_question_service.ListGenerativeQuestionConfigsResponse: """Post-rpc interceptor for list_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_list_generative_question_configs` interceptor runs + before the `post_list_generative_question_configs_with_metadata` interceptor. """ return response + def post_list_generative_question_configs_with_metadata( + self, + response: generative_question_service.ListGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.ListGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_list_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_list_generative_question_configs` interceptor. + When both interceptors are used, this `post_list_generative_question_configs_with_metadata` interceptor runs after the + `post_list_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_list_generative_question_configs` will be passed to + `post_list_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_update_generative_question_config( self, request: generative_question_service.UpdateGenerativeQuestionConfigRequest, @@ -219,12 +297,38 @@ def post_update_generative_question_config( ) -> generative_question.GenerativeQuestionConfig: """Post-rpc interceptor for update_generative_question_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_question_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_question_config` interceptor runs + before the `post_update_generative_question_config_with_metadata` interceptor. """ return response + def post_update_generative_question_config_with_metadata( + self, + response: generative_question.GenerativeQuestionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_question_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_question_config_with_metadata` + interceptor in new development instead of the `post_update_generative_question_config` interceptor. + When both interceptors are used, this `post_update_generative_question_config_with_metadata` interceptor runs after the + `post_update_generative_question_config` interceptor. The (possibly modified) response returned by + `post_update_generative_question_config` will be passed to + `post_update_generative_question_config_with_metadata`. + """ + return response, metadata + def pre_update_generative_questions_feature_config( self, request: generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest, @@ -245,12 +349,38 @@ def post_update_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for update_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_questions_feature_config` interceptor runs + before the `post_update_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_update_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_update_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_update_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_update_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_update_generative_questions_feature_config` will be passed to + `post_update_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -531,6 +661,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_update_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_batch_update_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -686,6 +823,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_generative_questions_feature_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -840,6 +984,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -997,6 +1148,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_generative_question_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_question_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1160,6 +1318,13 @@ def __call__( resp = self._interceptor.post_update_generative_questions_feature_config( resp ) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/client.py index ce918ca13bb3..5270e0fcfbff 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -527,6 +529,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1185,16 +1214,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1240,16 +1273,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/transports/rest.py index a676d3562f6c..02e5f3c02769 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/merchant_center_account_link_service/transports/rest.py @@ -117,12 +117,35 @@ def post_create_merchant_center_account_link( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_merchant_center_account_link - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_merchant_center_account_link_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MerchantCenterAccountLinkService server but before - it is returned to user code. + it is returned to user code. This `post_create_merchant_center_account_link` interceptor runs + before the `post_create_merchant_center_account_link_with_metadata` interceptor. """ return response + def post_create_merchant_center_account_link_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_merchant_center_account_link + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MerchantCenterAccountLinkService server but before it is returned to user code. + + We recommend only using this `post_create_merchant_center_account_link_with_metadata` + interceptor in new development instead of the `post_create_merchant_center_account_link` interceptor. + When both interceptors are used, this `post_create_merchant_center_account_link_with_metadata` interceptor runs after the + `post_create_merchant_center_account_link` interceptor. The (possibly modified) response returned by + `post_create_merchant_center_account_link` will be passed to + `post_create_merchant_center_account_link_with_metadata`. + """ + return response, metadata + def pre_delete_merchant_center_account_link( self, request: merchant_center_account_link_service.DeleteMerchantCenterAccountLinkRequest, @@ -159,12 +182,38 @@ def post_list_merchant_center_account_links( ) -> merchant_center_account_link_service.ListMerchantCenterAccountLinksResponse: """Post-rpc interceptor for list_merchant_center_account_links - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_merchant_center_account_links_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the MerchantCenterAccountLinkService server but before - it is returned to user code. + it is returned to user code. This `post_list_merchant_center_account_links` interceptor runs + before the `post_list_merchant_center_account_links_with_metadata` interceptor. """ return response + def post_list_merchant_center_account_links_with_metadata( + self, + response: merchant_center_account_link_service.ListMerchantCenterAccountLinksResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + merchant_center_account_link_service.ListMerchantCenterAccountLinksResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_merchant_center_account_links + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the MerchantCenterAccountLinkService server but before it is returned to user code. + + We recommend only using this `post_list_merchant_center_account_links_with_metadata` + interceptor in new development instead of the `post_list_merchant_center_account_links` interceptor. + When both interceptors are used, this `post_list_merchant_center_account_links_with_metadata` interceptor runs after the + `post_list_merchant_center_account_links` interceptor. The (possibly modified) response returned by + `post_list_merchant_center_account_links` will be passed to + `post_list_merchant_center_account_links_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -507,6 +556,13 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_merchant_center_account_link(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_create_merchant_center_account_link_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -784,6 +840,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_merchant_center_account_links(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_merchant_center_account_links_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/client.py index 7c75aeafc75e..a5f121053575 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -528,6 +530,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1717,16 +1746,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1772,16 +1805,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/transports/rest.py index 0d7620150100..5b393fe55de6 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/model_service/transports/rest.py @@ -158,12 +158,35 @@ def post_create_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_create_model` interceptor runs + before the `post_create_model_with_metadata` interceptor. """ return response + def post_create_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_create_model_with_metadata` + interceptor in new development instead of the `post_create_model` interceptor. + When both interceptors are used, this `post_create_model_with_metadata` interceptor runs after the + `post_create_model` interceptor. The (possibly modified) response returned by + `post_create_model` will be passed to + `post_create_model_with_metadata`. + """ + return response, metadata + def pre_delete_model( self, request: model_service.DeleteModelRequest, @@ -193,12 +216,33 @@ def pre_get_model( def post_get_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for get_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_get_model` interceptor runs + before the `post_get_model_with_metadata` interceptor. """ return response + def post_get_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_get_model_with_metadata` + interceptor in new development instead of the `post_get_model` interceptor. + When both interceptors are used, this `post_get_model_with_metadata` interceptor runs after the + `post_get_model` interceptor. The (possibly modified) response returned by + `post_get_model` will be passed to + `post_get_model_with_metadata`. + """ + return response, metadata + def pre_list_models( self, request: model_service.ListModelsRequest, @@ -218,12 +262,37 @@ def post_list_models( ) -> model_service.ListModelsResponse: """Post-rpc interceptor for list_models - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_models_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_list_models` interceptor runs + before the `post_list_models_with_metadata` interceptor. """ return response + def post_list_models_with_metadata( + self, + response: model_service.ListModelsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + model_service.ListModelsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_models + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_list_models_with_metadata` + interceptor in new development instead of the `post_list_models` interceptor. + When both interceptors are used, this `post_list_models_with_metadata` interceptor runs after the + `post_list_models` interceptor. The (possibly modified) response returned by + `post_list_models` will be passed to + `post_list_models_with_metadata`. + """ + return response, metadata + def pre_pause_model( self, request: model_service.PauseModelRequest, @@ -241,12 +310,33 @@ def pre_pause_model( def post_pause_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for pause_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_pause_model` interceptor runs + before the `post_pause_model_with_metadata` interceptor. """ return response + def post_pause_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_pause_model_with_metadata` + interceptor in new development instead of the `post_pause_model` interceptor. + When both interceptors are used, this `post_pause_model_with_metadata` interceptor runs after the + `post_pause_model` interceptor. The (possibly modified) response returned by + `post_pause_model` will be passed to + `post_pause_model_with_metadata`. + """ + return response, metadata + def pre_resume_model( self, request: model_service.ResumeModelRequest, @@ -264,12 +354,33 @@ def pre_resume_model( def post_resume_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for resume_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_resume_model` interceptor runs + before the `post_resume_model_with_metadata` interceptor. """ return response + def post_resume_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_resume_model_with_metadata` + interceptor in new development instead of the `post_resume_model` interceptor. + When both interceptors are used, this `post_resume_model_with_metadata` interceptor runs after the + `post_resume_model` interceptor. The (possibly modified) response returned by + `post_resume_model` will be passed to + `post_resume_model_with_metadata`. + """ + return response, metadata + def pre_tune_model( self, request: model_service.TuneModelRequest, @@ -287,12 +398,35 @@ def post_tune_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for tune_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_tune_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_tune_model` interceptor runs + before the `post_tune_model_with_metadata` interceptor. """ return response + def post_tune_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for tune_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_tune_model_with_metadata` + interceptor in new development instead of the `post_tune_model` interceptor. + When both interceptors are used, this `post_tune_model_with_metadata` interceptor runs after the + `post_tune_model` interceptor. The (possibly modified) response returned by + `post_tune_model` will be passed to + `post_tune_model_with_metadata`. + """ + return response, metadata + def pre_update_model( self, request: model_service.UpdateModelRequest, @@ -310,12 +444,35 @@ def pre_update_model( def post_update_model(self, response: gcr_model.Model) -> gcr_model.Model: """Post-rpc interceptor for update_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_update_model` interceptor runs + before the `post_update_model_with_metadata` interceptor. """ return response + def post_update_model_with_metadata( + self, + response: gcr_model.Model, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_update_model_with_metadata` + interceptor in new development instead of the `post_update_model` interceptor. + When both interceptors are used, this `post_update_model_with_metadata` interceptor runs after the + `post_update_model` interceptor. The (possibly modified) response returned by + `post_update_model` will be passed to + `post_update_model_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -659,6 +816,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -918,6 +1079,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1063,6 +1228,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_models(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_models_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1225,6 +1394,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1385,6 +1558,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1539,6 +1716,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_tune_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_tune_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1699,6 +1880,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/client.py index c4f21cb0be00..ad0c16c66710 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/transports/rest.py index e5047b444943..4bc749bfe3a8 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/prediction_service/transports/rest.py @@ -103,12 +103,37 @@ def post_predict( ) -> prediction_service.PredictResponse: """Post-rpc interceptor for predict - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_predict_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionService server but before - it is returned to user code. + it is returned to user code. This `post_predict` interceptor runs + before the `post_predict_with_metadata` interceptor. """ return response + def post_predict_with_metadata( + self, + response: prediction_service.PredictResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_service.PredictResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for predict + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionService server but before it is returned to user code. + + We recommend only using this `post_predict_with_metadata` + interceptor in new development instead of the `post_predict` interceptor. + When both interceptors are used, this `post_predict_with_metadata` interceptor runs after the + `post_predict` interceptor. The (possibly modified) response returned by + `post_predict` will be passed to + `post_predict_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -373,6 +398,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_predict(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_predict_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/client.py index 25a3db649cff..73e789f678d6 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -526,6 +528,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2683,16 +2712,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2738,16 +2771,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/transports/rest.py index bec06b3f8b1f..e2b1523e45bf 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/product_service/transports/rest.py @@ -200,12 +200,35 @@ def post_add_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_fulfillment_places` interceptor runs + before the `post_add_fulfillment_places_with_metadata` interceptor. """ return response + def post_add_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_add_fulfillment_places` interceptor. + When both interceptors are used, this `post_add_fulfillment_places_with_metadata` interceptor runs after the + `post_add_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_add_fulfillment_places` will be passed to + `post_add_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_add_local_inventories( self, request: product_service.AddLocalInventoriesRequest, @@ -226,12 +249,35 @@ def post_add_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_local_inventories` interceptor runs + before the `post_add_local_inventories_with_metadata` interceptor. """ return response + def post_add_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_local_inventories_with_metadata` + interceptor in new development instead of the `post_add_local_inventories` interceptor. + When both interceptors are used, this `post_add_local_inventories_with_metadata` interceptor runs after the + `post_add_local_inventories` interceptor. The (possibly modified) response returned by + `post_add_local_inventories` will be passed to + `post_add_local_inventories_with_metadata`. + """ + return response, metadata + def pre_create_product( self, request: product_service.CreateProductRequest, @@ -249,12 +295,35 @@ def pre_create_product( def post_create_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for create_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_create_product` interceptor runs + before the `post_create_product_with_metadata` interceptor. """ return response + def post_create_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_create_product_with_metadata` + interceptor in new development instead of the `post_create_product` interceptor. + When both interceptors are used, this `post_create_product_with_metadata` interceptor runs after the + `post_create_product` interceptor. The (possibly modified) response returned by + `post_create_product` will be passed to + `post_create_product_with_metadata`. + """ + return response, metadata + def pre_delete_product( self, request: product_service.DeleteProductRequest, @@ -288,12 +357,35 @@ def post_export_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_export_products` interceptor runs + before the `post_export_products_with_metadata` interceptor. """ return response + def post_export_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_export_products_with_metadata` + interceptor in new development instead of the `post_export_products` interceptor. + When both interceptors are used, this `post_export_products_with_metadata` interceptor runs after the + `post_export_products` interceptor. The (possibly modified) response returned by + `post_export_products` will be passed to + `post_export_products_with_metadata`. + """ + return response, metadata + def pre_get_product( self, request: product_service.GetProductRequest, @@ -311,12 +403,35 @@ def pre_get_product( def post_get_product(self, response: product.Product) -> product.Product: """Post-rpc interceptor for get_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_get_product` interceptor runs + before the `post_get_product_with_metadata` interceptor. """ return response + def post_get_product_with_metadata( + self, + response: product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_get_product_with_metadata` + interceptor in new development instead of the `post_get_product` interceptor. + When both interceptors are used, this `post_get_product_with_metadata` interceptor runs after the + `post_get_product` interceptor. The (possibly modified) response returned by + `post_get_product` will be passed to + `post_get_product_with_metadata`. + """ + return response, metadata + def pre_import_products( self, request: import_config.ImportProductsRequest, @@ -336,12 +451,35 @@ def post_import_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_import_products` interceptor runs + before the `post_import_products_with_metadata` interceptor. """ return response + def post_import_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_import_products_with_metadata` + interceptor in new development instead of the `post_import_products` interceptor. + When both interceptors are used, this `post_import_products_with_metadata` interceptor runs after the + `post_import_products` interceptor. The (possibly modified) response returned by + `post_import_products` will be passed to + `post_import_products_with_metadata`. + """ + return response, metadata + def pre_list_products( self, request: product_service.ListProductsRequest, @@ -361,12 +499,37 @@ def post_list_products( ) -> product_service.ListProductsResponse: """Post-rpc interceptor for list_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_list_products` interceptor runs + before the `post_list_products_with_metadata` interceptor. """ return response + def post_list_products_with_metadata( + self, + response: product_service.ListProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + product_service.ListProductsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_list_products_with_metadata` + interceptor in new development instead of the `post_list_products` interceptor. + When both interceptors are used, this `post_list_products_with_metadata` interceptor runs after the + `post_list_products` interceptor. The (possibly modified) response returned by + `post_list_products` will be passed to + `post_list_products_with_metadata`. + """ + return response, metadata + def pre_purge_products( self, request: purge_config.PurgeProductsRequest, @@ -386,12 +549,35 @@ def post_purge_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_purge_products` interceptor runs + before the `post_purge_products_with_metadata` interceptor. """ return response + def post_purge_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_purge_products_with_metadata` + interceptor in new development instead of the `post_purge_products` interceptor. + When both interceptors are used, this `post_purge_products_with_metadata` interceptor runs after the + `post_purge_products` interceptor. The (possibly modified) response returned by + `post_purge_products` will be passed to + `post_purge_products_with_metadata`. + """ + return response, metadata + def pre_remove_fulfillment_places( self, request: product_service.RemoveFulfillmentPlacesRequest, @@ -412,12 +598,35 @@ def post_remove_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_fulfillment_places` interceptor runs + before the `post_remove_fulfillment_places_with_metadata` interceptor. """ return response + def post_remove_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_remove_fulfillment_places` interceptor. + When both interceptors are used, this `post_remove_fulfillment_places_with_metadata` interceptor runs after the + `post_remove_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_remove_fulfillment_places` will be passed to + `post_remove_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_remove_local_inventories( self, request: product_service.RemoveLocalInventoriesRequest, @@ -438,12 +647,35 @@ def post_remove_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_local_inventories` interceptor runs + before the `post_remove_local_inventories_with_metadata` interceptor. """ return response + def post_remove_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_local_inventories_with_metadata` + interceptor in new development instead of the `post_remove_local_inventories` interceptor. + When both interceptors are used, this `post_remove_local_inventories_with_metadata` interceptor runs after the + `post_remove_local_inventories` interceptor. The (possibly modified) response returned by + `post_remove_local_inventories` will be passed to + `post_remove_local_inventories_with_metadata`. + """ + return response, metadata + def pre_set_inventory( self, request: product_service.SetInventoryRequest, @@ -463,12 +695,35 @@ def post_set_inventory( ) -> operations_pb2.Operation: """Post-rpc interceptor for set_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_set_inventory` interceptor runs + before the `post_set_inventory_with_metadata` interceptor. """ return response + def post_set_inventory_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_set_inventory_with_metadata` + interceptor in new development instead of the `post_set_inventory` interceptor. + When both interceptors are used, this `post_set_inventory_with_metadata` interceptor runs after the + `post_set_inventory` interceptor. The (possibly modified) response returned by + `post_set_inventory` will be passed to + `post_set_inventory_with_metadata`. + """ + return response, metadata + def pre_update_product( self, request: product_service.UpdateProductRequest, @@ -486,12 +741,35 @@ def pre_update_product( def post_update_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for update_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_update_product` interceptor runs + before the `post_update_product_with_metadata` interceptor. """ return response + def post_update_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_update_product_with_metadata` + interceptor in new development instead of the `post_update_product` interceptor. + When both interceptors are used, this `post_update_product_with_metadata` interceptor runs after the + `post_update_product` interceptor. The (possibly modified) response returned by + `post_update_product` will be passed to + `post_update_product_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -824,6 +1102,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -976,6 +1258,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1127,6 +1413,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1383,6 +1673,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1530,6 +1824,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1677,6 +1975,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1822,6 +2124,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1972,6 +2278,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2126,6 +2436,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2280,6 +2594,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2429,6 +2747,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2580,6 +2902,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/client.py index d9440a962415..7cb7b7c1b83c 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1681,16 +1710,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1736,16 +1769,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/transports/rest.py index 3ab41facc383..6c1a349f43b0 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/project_service/transports/rest.py @@ -159,12 +159,35 @@ def pre_accept_terms( def post_accept_terms(self, response: gcr_project.Project) -> gcr_project.Project: """Post-rpc interceptor for accept_terms - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_accept_terms_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_accept_terms` interceptor runs + before the `post_accept_terms_with_metadata` interceptor. """ return response + def post_accept_terms_with_metadata( + self, + response: gcr_project.Project, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_project.Project, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for accept_terms + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_accept_terms_with_metadata` + interceptor in new development instead of the `post_accept_terms` interceptor. + When both interceptors are used, this `post_accept_terms_with_metadata` interceptor runs after the + `post_accept_terms` interceptor. The (possibly modified) response returned by + `post_accept_terms` will be passed to + `post_accept_terms_with_metadata`. + """ + return response, metadata + def pre_enroll_solution( self, request: project_service.EnrollSolutionRequest, @@ -184,12 +207,35 @@ def post_enroll_solution( ) -> operations_pb2.Operation: """Post-rpc interceptor for enroll_solution - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_enroll_solution_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_enroll_solution` interceptor runs + before the `post_enroll_solution_with_metadata` interceptor. """ return response + def post_enroll_solution_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for enroll_solution + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_enroll_solution_with_metadata` + interceptor in new development instead of the `post_enroll_solution` interceptor. + When both interceptors are used, this `post_enroll_solution_with_metadata` interceptor runs after the + `post_enroll_solution` interceptor. The (possibly modified) response returned by + `post_enroll_solution` will be passed to + `post_enroll_solution_with_metadata`. + """ + return response, metadata + def pre_get_alert_config( self, request: project_service.GetAlertConfigRequest, @@ -209,12 +255,35 @@ def post_get_alert_config( ) -> project.AlertConfig: """Post-rpc interceptor for get_alert_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_alert_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_get_alert_config` interceptor runs + before the `post_get_alert_config_with_metadata` interceptor. """ return response + def post_get_alert_config_with_metadata( + self, + response: project.AlertConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.AlertConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_alert_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_get_alert_config_with_metadata` + interceptor in new development instead of the `post_get_alert_config` interceptor. + When both interceptors are used, this `post_get_alert_config_with_metadata` interceptor runs after the + `post_get_alert_config` interceptor. The (possibly modified) response returned by + `post_get_alert_config` will be passed to + `post_get_alert_config_with_metadata`. + """ + return response, metadata + def pre_get_logging_config( self, request: project_service.GetLoggingConfigRequest, @@ -234,12 +303,35 @@ def post_get_logging_config( ) -> project.LoggingConfig: """Post-rpc interceptor for get_logging_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_logging_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_get_logging_config` interceptor runs + before the `post_get_logging_config_with_metadata` interceptor. """ return response + def post_get_logging_config_with_metadata( + self, + response: project.LoggingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.LoggingConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_logging_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_get_logging_config_with_metadata` + interceptor in new development instead of the `post_get_logging_config` interceptor. + When both interceptors are used, this `post_get_logging_config_with_metadata` interceptor runs after the + `post_get_logging_config` interceptor. The (possibly modified) response returned by + `post_get_logging_config` will be passed to + `post_get_logging_config_with_metadata`. + """ + return response, metadata + def pre_get_project( self, request: project_service.GetProjectRequest, @@ -257,12 +349,35 @@ def pre_get_project( def post_get_project(self, response: project.Project) -> project.Project: """Post-rpc interceptor for get_project - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_project_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_get_project` interceptor runs + before the `post_get_project_with_metadata` interceptor. """ return response + def post_get_project_with_metadata( + self, + response: project.Project, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.Project, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_project + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_get_project_with_metadata` + interceptor in new development instead of the `post_get_project` interceptor. + When both interceptors are used, this `post_get_project_with_metadata` interceptor runs after the + `post_get_project` interceptor. The (possibly modified) response returned by + `post_get_project` will be passed to + `post_get_project_with_metadata`. + """ + return response, metadata + def pre_list_enrolled_solutions( self, request: project_service.ListEnrolledSolutionsRequest, @@ -283,12 +398,38 @@ def post_list_enrolled_solutions( ) -> project_service.ListEnrolledSolutionsResponse: """Post-rpc interceptor for list_enrolled_solutions - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_enrolled_solutions_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_list_enrolled_solutions` interceptor runs + before the `post_list_enrolled_solutions_with_metadata` interceptor. """ return response + def post_list_enrolled_solutions_with_metadata( + self, + response: project_service.ListEnrolledSolutionsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + project_service.ListEnrolledSolutionsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_enrolled_solutions + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_list_enrolled_solutions_with_metadata` + interceptor in new development instead of the `post_list_enrolled_solutions` interceptor. + When both interceptors are used, this `post_list_enrolled_solutions_with_metadata` interceptor runs after the + `post_list_enrolled_solutions` interceptor. The (possibly modified) response returned by + `post_list_enrolled_solutions` will be passed to + `post_list_enrolled_solutions_with_metadata`. + """ + return response, metadata + def pre_update_alert_config( self, request: project_service.UpdateAlertConfigRequest, @@ -309,12 +450,35 @@ def post_update_alert_config( ) -> project.AlertConfig: """Post-rpc interceptor for update_alert_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_alert_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_update_alert_config` interceptor runs + before the `post_update_alert_config_with_metadata` interceptor. """ return response + def post_update_alert_config_with_metadata( + self, + response: project.AlertConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.AlertConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_alert_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_update_alert_config_with_metadata` + interceptor in new development instead of the `post_update_alert_config` interceptor. + When both interceptors are used, this `post_update_alert_config_with_metadata` interceptor runs after the + `post_update_alert_config` interceptor. The (possibly modified) response returned by + `post_update_alert_config` will be passed to + `post_update_alert_config_with_metadata`. + """ + return response, metadata + def pre_update_logging_config( self, request: project_service.UpdateLoggingConfigRequest, @@ -335,12 +499,35 @@ def post_update_logging_config( ) -> project.LoggingConfig: """Post-rpc interceptor for update_logging_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_logging_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_update_logging_config` interceptor runs + before the `post_update_logging_config_with_metadata` interceptor. """ return response + def post_update_logging_config_with_metadata( + self, + response: project.LoggingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.LoggingConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_logging_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_update_logging_config_with_metadata` + interceptor in new development instead of the `post_update_logging_config` interceptor. + When both interceptors are used, this `post_update_logging_config_with_metadata` interceptor runs after the + `post_update_logging_config` interceptor. The (possibly modified) response returned by + `post_update_logging_config` will be passed to + `post_update_logging_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -668,6 +855,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_accept_terms(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_accept_terms_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -815,6 +1006,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_enroll_solution(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_enroll_solution_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -959,6 +1154,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_alert_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_alert_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1106,6 +1305,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_logging_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_logging_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1250,6 +1453,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_project(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_project_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1396,6 +1603,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_enrolled_solutions(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_enrolled_solutions_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1548,6 +1759,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_alert_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_alert_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1702,6 +1917,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_logging_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_logging_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/client.py index 6ba6dd2abe8e..fc8b2366a533 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -566,6 +568,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -927,16 +956,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -982,16 +1015,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/transports/rest.py index 92a29e0a5eac..e0839aa3db50 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/search_service/transports/rest.py @@ -101,12 +101,35 @@ def post_search( ) -> search_service.SearchResponse: """Post-rpc interceptor for search - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the SearchService server but before - it is returned to user code. + it is returned to user code. This `post_search` interceptor runs + before the `post_search_with_metadata` interceptor. """ return response + def post_search_with_metadata( + self, + response: search_service.SearchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[search_service.SearchResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for search + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the SearchService server but before it is returned to user code. + + We recommend only using this `post_search_with_metadata` + interceptor in new development instead of the `post_search` interceptor. + When both interceptors are used, this `post_search_with_metadata` interceptor runs after the + `post_search` interceptor. The (possibly modified) response returned by + `post_search` will be passed to + `post_search_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -378,6 +401,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/client.py index 0843e6a3a57d..10a4c64978c5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1610,16 +1639,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1665,16 +1698,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/transports/rest.py index 77e9d020776a..4fe4d8778b64 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/serving_config_service/transports/rest.py @@ -151,12 +151,37 @@ def post_add_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for add_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_add_control` interceptor runs + before the `post_add_control_with_metadata` interceptor. """ return response + def post_add_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for add_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_add_control_with_metadata` + interceptor in new development instead of the `post_add_control` interceptor. + When both interceptors are used, this `post_add_control_with_metadata` interceptor runs after the + `post_add_control` interceptor. The (possibly modified) response returned by + `post_add_control` will be passed to + `post_add_control_with_metadata`. + """ + return response, metadata + def pre_create_serving_config( self, request: serving_config_service.CreateServingConfigRequest, @@ -177,12 +202,37 @@ def post_create_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for create_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_create_serving_config` interceptor runs + before the `post_create_serving_config_with_metadata` interceptor. """ return response + def post_create_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for create_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_create_serving_config_with_metadata` + interceptor in new development instead of the `post_create_serving_config` interceptor. + When both interceptors are used, this `post_create_serving_config_with_metadata` interceptor runs after the + `post_create_serving_config` interceptor. The (possibly modified) response returned by + `post_create_serving_config` will be passed to + `post_create_serving_config_with_metadata`. + """ + return response, metadata + def pre_delete_serving_config( self, request: serving_config_service.DeleteServingConfigRequest, @@ -218,12 +268,35 @@ def post_get_serving_config( ) -> serving_config.ServingConfig: """Post-rpc interceptor for get_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_get_serving_config` interceptor runs + before the `post_get_serving_config_with_metadata` interceptor. """ return response + def post_get_serving_config_with_metadata( + self, + response: serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_get_serving_config_with_metadata` + interceptor in new development instead of the `post_get_serving_config` interceptor. + When both interceptors are used, this `post_get_serving_config_with_metadata` interceptor runs after the + `post_get_serving_config` interceptor. The (possibly modified) response returned by + `post_get_serving_config` will be passed to + `post_get_serving_config_with_metadata`. + """ + return response, metadata + def pre_list_serving_configs( self, request: serving_config_service.ListServingConfigsRequest, @@ -244,12 +317,38 @@ def post_list_serving_configs( ) -> serving_config_service.ListServingConfigsResponse: """Post-rpc interceptor for list_serving_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_serving_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_list_serving_configs` interceptor runs + before the `post_list_serving_configs_with_metadata` interceptor. """ return response + def post_list_serving_configs_with_metadata( + self, + response: serving_config_service.ListServingConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + serving_config_service.ListServingConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_serving_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_list_serving_configs_with_metadata` + interceptor in new development instead of the `post_list_serving_configs` interceptor. + When both interceptors are used, this `post_list_serving_configs_with_metadata` interceptor runs after the + `post_list_serving_configs` interceptor. The (possibly modified) response returned by + `post_list_serving_configs` will be passed to + `post_list_serving_configs_with_metadata`. + """ + return response, metadata + def pre_remove_control( self, request: serving_config_service.RemoveControlRequest, @@ -270,12 +369,37 @@ def post_remove_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for remove_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_remove_control` interceptor runs + before the `post_remove_control_with_metadata` interceptor. """ return response + def post_remove_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for remove_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_remove_control_with_metadata` + interceptor in new development instead of the `post_remove_control` interceptor. + When both interceptors are used, this `post_remove_control_with_metadata` interceptor runs after the + `post_remove_control` interceptor. The (possibly modified) response returned by + `post_remove_control` will be passed to + `post_remove_control_with_metadata`. + """ + return response, metadata + def pre_update_serving_config( self, request: serving_config_service.UpdateServingConfigRequest, @@ -296,12 +420,37 @@ def post_update_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for update_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_update_serving_config` interceptor runs + before the `post_update_serving_config_with_metadata` interceptor. """ return response + def post_update_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_update_serving_config_with_metadata` + interceptor in new development instead of the `post_update_serving_config` interceptor. + When both interceptors are used, this `post_update_serving_config_with_metadata` interceptor runs after the + `post_update_serving_config` interceptor. The (possibly modified) response returned by + `post_update_serving_config` will be passed to + `post_update_serving_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -567,6 +716,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -725,6 +878,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -988,6 +1145,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1136,6 +1297,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_serving_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_serving_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1291,6 +1456,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1449,6 +1618,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/client.py index 6c15825b8e72..fb6a0aa6cc4f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -526,6 +528,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1445,16 +1474,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1500,16 +1533,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/transports/rest.py index 167e65b03814..3fcfd863b9bf 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/services/user_event_service/transports/rest.py @@ -151,12 +151,35 @@ def post_collect_user_event( ) -> httpbody_pb2.HttpBody: """Post-rpc interceptor for collect_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_collect_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_collect_user_event` interceptor runs + before the `post_collect_user_event_with_metadata` interceptor. """ return response + def post_collect_user_event_with_metadata( + self, + response: httpbody_pb2.HttpBody, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[httpbody_pb2.HttpBody, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for collect_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_collect_user_event_with_metadata` + interceptor in new development instead of the `post_collect_user_event` interceptor. + When both interceptors are used, this `post_collect_user_event_with_metadata` interceptor runs after the + `post_collect_user_event` interceptor. The (possibly modified) response returned by + `post_collect_user_event` will be passed to + `post_collect_user_event_with_metadata`. + """ + return response, metadata + def pre_export_user_events( self, request: export_config.ExportUserEventsRequest, @@ -176,12 +199,35 @@ def post_export_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_export_user_events` interceptor runs + before the `post_export_user_events_with_metadata` interceptor. """ return response + def post_export_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_export_user_events_with_metadata` + interceptor in new development instead of the `post_export_user_events` interceptor. + When both interceptors are used, this `post_export_user_events_with_metadata` interceptor runs after the + `post_export_user_events` interceptor. The (possibly modified) response returned by + `post_export_user_events` will be passed to + `post_export_user_events_with_metadata`. + """ + return response, metadata + def pre_import_user_events( self, request: import_config.ImportUserEventsRequest, @@ -201,12 +247,35 @@ def post_import_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_import_user_events` interceptor runs + before the `post_import_user_events_with_metadata` interceptor. """ return response + def post_import_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_import_user_events_with_metadata` + interceptor in new development instead of the `post_import_user_events` interceptor. + When both interceptors are used, this `post_import_user_events_with_metadata` interceptor runs after the + `post_import_user_events` interceptor. The (possibly modified) response returned by + `post_import_user_events` will be passed to + `post_import_user_events_with_metadata`. + """ + return response, metadata + def pre_purge_user_events( self, request: purge_config.PurgeUserEventsRequest, @@ -226,12 +295,35 @@ def post_purge_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_purge_user_events` interceptor runs + before the `post_purge_user_events_with_metadata` interceptor. """ return response + def post_purge_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_purge_user_events_with_metadata` + interceptor in new development instead of the `post_purge_user_events` interceptor. + When both interceptors are used, this `post_purge_user_events_with_metadata` interceptor runs after the + `post_purge_user_events` interceptor. The (possibly modified) response returned by + `post_purge_user_events` will be passed to + `post_purge_user_events_with_metadata`. + """ + return response, metadata + def pre_rejoin_user_events( self, request: user_event_service.RejoinUserEventsRequest, @@ -252,12 +344,35 @@ def post_rejoin_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for rejoin_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_rejoin_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_rejoin_user_events` interceptor runs + before the `post_rejoin_user_events_with_metadata` interceptor. """ return response + def post_rejoin_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for rejoin_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_rejoin_user_events_with_metadata` + interceptor in new development instead of the `post_rejoin_user_events` interceptor. + When both interceptors are used, this `post_rejoin_user_events_with_metadata` interceptor runs after the + `post_rejoin_user_events` interceptor. The (possibly modified) response returned by + `post_rejoin_user_events` will be passed to + `post_rejoin_user_events_with_metadata`. + """ + return response, metadata + def pre_write_user_event( self, request: user_event_service.WriteUserEventRequest, @@ -278,12 +393,35 @@ def post_write_user_event( ) -> user_event.UserEvent: """Post-rpc interceptor for write_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_write_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_write_user_event` interceptor runs + before the `post_write_user_event_with_metadata` interceptor. """ return response + def post_write_user_event_with_metadata( + self, + response: user_event.UserEvent, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[user_event.UserEvent, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for write_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_write_user_event_with_metadata` + interceptor in new development instead of the `post_write_user_event` interceptor. + When both interceptors are used, this `post_write_user_event_with_metadata` interceptor runs after the + `post_write_user_event` interceptor. The (possibly modified) response returned by + `post_write_user_event` will be passed to + `post_write_user_event_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -657,6 +795,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_collect_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_collect_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -807,6 +949,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -958,6 +1104,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1109,6 +1259,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1260,6 +1414,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_rejoin_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_rejoin_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1413,6 +1571,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_write_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_write_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py index 45f4e360312c..558c8aab67c5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.24.0" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/client.py index a798234a4af4..623ae28dd23f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -469,6 +471,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/transports/rest.py index cb05445877d1..0c5393e1b4d6 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/analytics_service/transports/rest.py @@ -104,12 +104,35 @@ def post_export_analytics_metrics( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_analytics_metrics - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_analytics_metrics_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the AnalyticsService server but before - it is returned to user code. + it is returned to user code. This `post_export_analytics_metrics` interceptor runs + before the `post_export_analytics_metrics_with_metadata` interceptor. """ return response + def post_export_analytics_metrics_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_analytics_metrics + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the AnalyticsService server but before it is returned to user code. + + We recommend only using this `post_export_analytics_metrics_with_metadata` + interceptor in new development instead of the `post_export_analytics_metrics` interceptor. + When both interceptors are used, this `post_export_analytics_metrics_with_metadata` interceptor runs after the + `post_export_analytics_metrics` interceptor. The (possibly modified) response returned by + `post_export_analytics_metrics` will be passed to + `post_export_analytics_metrics_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -440,6 +463,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_analytics_metrics(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_analytics_metrics_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/client.py index bc34c289c0f2..f2839cdddd94 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -559,6 +561,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2189,16 +2218,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2244,16 +2277,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/transports/rest.py index adbf95bf2b9a..46c8259d82cc 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/catalog_service/transports/rest.py @@ -191,12 +191,35 @@ def post_add_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for add_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_add_catalog_attribute` interceptor runs + before the `post_add_catalog_attribute_with_metadata` interceptor. """ return response + def post_add_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_add_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_add_catalog_attribute` interceptor. + When both interceptors are used, this `post_add_catalog_attribute_with_metadata` interceptor runs after the + `post_add_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_add_catalog_attribute` will be passed to + `post_add_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_batch_remove_catalog_attributes( self, request: catalog_service.BatchRemoveCatalogAttributesRequest, @@ -217,12 +240,38 @@ def post_batch_remove_catalog_attributes( ) -> catalog_service.BatchRemoveCatalogAttributesResponse: """Post-rpc interceptor for batch_remove_catalog_attributes - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_remove_catalog_attributes_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_batch_remove_catalog_attributes` interceptor runs + before the `post_batch_remove_catalog_attributes_with_metadata` interceptor. """ return response + def post_batch_remove_catalog_attributes_with_metadata( + self, + response: catalog_service.BatchRemoveCatalogAttributesResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.BatchRemoveCatalogAttributesResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for batch_remove_catalog_attributes + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_batch_remove_catalog_attributes_with_metadata` + interceptor in new development instead of the `post_batch_remove_catalog_attributes` interceptor. + When both interceptors are used, this `post_batch_remove_catalog_attributes_with_metadata` interceptor runs after the + `post_batch_remove_catalog_attributes` interceptor. The (possibly modified) response returned by + `post_batch_remove_catalog_attributes` will be passed to + `post_batch_remove_catalog_attributes_with_metadata`. + """ + return response, metadata + def pre_get_attributes_config( self, request: catalog_service.GetAttributesConfigRequest, @@ -243,12 +292,35 @@ def post_get_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for get_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_attributes_config` interceptor runs + before the `post_get_attributes_config_with_metadata` interceptor. """ return response + def post_get_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_attributes_config_with_metadata` + interceptor in new development instead of the `post_get_attributes_config` interceptor. + When both interceptors are used, this `post_get_attributes_config_with_metadata` interceptor runs after the + `post_get_attributes_config` interceptor. The (possibly modified) response returned by + `post_get_attributes_config` will be passed to + `post_get_attributes_config_with_metadata`. + """ + return response, metadata + def pre_get_completion_config( self, request: catalog_service.GetCompletionConfigRequest, @@ -269,12 +341,35 @@ def post_get_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for get_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_completion_config` interceptor runs + before the `post_get_completion_config_with_metadata` interceptor. """ return response + def post_get_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_completion_config_with_metadata` + interceptor in new development instead of the `post_get_completion_config` interceptor. + When both interceptors are used, this `post_get_completion_config_with_metadata` interceptor runs after the + `post_get_completion_config` interceptor. The (possibly modified) response returned by + `post_get_completion_config` will be passed to + `post_get_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_default_branch( self, request: catalog_service.GetDefaultBranchRequest, @@ -294,12 +389,38 @@ def post_get_default_branch( ) -> catalog_service.GetDefaultBranchResponse: """Post-rpc interceptor for get_default_branch - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_default_branch_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_get_default_branch` interceptor runs + before the `post_get_default_branch_with_metadata` interceptor. """ return response + def post_get_default_branch_with_metadata( + self, + response: catalog_service.GetDefaultBranchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.GetDefaultBranchResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_default_branch + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_get_default_branch_with_metadata` + interceptor in new development instead of the `post_get_default_branch` interceptor. + When both interceptors are used, this `post_get_default_branch_with_metadata` interceptor runs after the + `post_get_default_branch` interceptor. The (possibly modified) response returned by + `post_get_default_branch` will be passed to + `post_get_default_branch_with_metadata`. + """ + return response, metadata + def pre_list_catalogs( self, request: catalog_service.ListCatalogsRequest, @@ -319,12 +440,37 @@ def post_list_catalogs( ) -> catalog_service.ListCatalogsResponse: """Post-rpc interceptor for list_catalogs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_catalogs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_list_catalogs` interceptor runs + before the `post_list_catalogs_with_metadata` interceptor. """ return response + def post_list_catalogs_with_metadata( + self, + response: catalog_service.ListCatalogsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + catalog_service.ListCatalogsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_catalogs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_list_catalogs_with_metadata` + interceptor in new development instead of the `post_list_catalogs` interceptor. + When both interceptors are used, this `post_list_catalogs_with_metadata` interceptor runs after the + `post_list_catalogs` interceptor. The (possibly modified) response returned by + `post_list_catalogs` will be passed to + `post_list_catalogs_with_metadata`. + """ + return response, metadata + def pre_remove_catalog_attribute( self, request: catalog_service.RemoveCatalogAttributeRequest, @@ -345,12 +491,35 @@ def post_remove_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for remove_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_remove_catalog_attribute` interceptor runs + before the `post_remove_catalog_attribute_with_metadata` interceptor. """ return response + def post_remove_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_remove_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_remove_catalog_attribute` interceptor. + When both interceptors are used, this `post_remove_catalog_attribute_with_metadata` interceptor runs after the + `post_remove_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_remove_catalog_attribute` will be passed to + `post_remove_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_replace_catalog_attribute( self, request: catalog_service.ReplaceCatalogAttributeRequest, @@ -371,12 +540,35 @@ def post_replace_catalog_attribute( ) -> catalog.AttributesConfig: """Post-rpc interceptor for replace_catalog_attribute - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_replace_catalog_attribute_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_replace_catalog_attribute` interceptor runs + before the `post_replace_catalog_attribute_with_metadata` interceptor. """ return response + def post_replace_catalog_attribute_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for replace_catalog_attribute + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_replace_catalog_attribute_with_metadata` + interceptor in new development instead of the `post_replace_catalog_attribute` interceptor. + When both interceptors are used, this `post_replace_catalog_attribute_with_metadata` interceptor runs after the + `post_replace_catalog_attribute` interceptor. The (possibly modified) response returned by + `post_replace_catalog_attribute` will be passed to + `post_replace_catalog_attribute_with_metadata`. + """ + return response, metadata + def pre_set_default_branch( self, request: catalog_service.SetDefaultBranchRequest, @@ -411,12 +603,35 @@ def post_update_attributes_config( ) -> catalog.AttributesConfig: """Post-rpc interceptor for update_attributes_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_attributes_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_attributes_config` interceptor runs + before the `post_update_attributes_config_with_metadata` interceptor. """ return response + def post_update_attributes_config_with_metadata( + self, + response: catalog.AttributesConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.AttributesConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_attributes_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_attributes_config_with_metadata` + interceptor in new development instead of the `post_update_attributes_config` interceptor. + When both interceptors are used, this `post_update_attributes_config_with_metadata` interceptor runs after the + `post_update_attributes_config` interceptor. The (possibly modified) response returned by + `post_update_attributes_config` will be passed to + `post_update_attributes_config_with_metadata`. + """ + return response, metadata + def pre_update_catalog( self, request: catalog_service.UpdateCatalogRequest, @@ -434,12 +649,35 @@ def pre_update_catalog( def post_update_catalog(self, response: gcr_catalog.Catalog) -> gcr_catalog.Catalog: """Post-rpc interceptor for update_catalog - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_catalog_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_catalog` interceptor runs + before the `post_update_catalog_with_metadata` interceptor. """ return response + def post_update_catalog_with_metadata( + self, + response: gcr_catalog.Catalog, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_catalog.Catalog, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_catalog + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_catalog_with_metadata` + interceptor in new development instead of the `post_update_catalog` interceptor. + When both interceptors are used, this `post_update_catalog_with_metadata` interceptor runs after the + `post_update_catalog` interceptor. The (possibly modified) response returned by + `post_update_catalog` will be passed to + `post_update_catalog_with_metadata`. + """ + return response, metadata + def pre_update_completion_config( self, request: catalog_service.UpdateCompletionConfigRequest, @@ -460,12 +698,35 @@ def post_update_completion_config( ) -> catalog.CompletionConfig: """Post-rpc interceptor for update_completion_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_completion_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CatalogService server but before - it is returned to user code. + it is returned to user code. This `post_update_completion_config` interceptor runs + before the `post_update_completion_config_with_metadata` interceptor. """ return response + def post_update_completion_config_with_metadata( + self, + response: catalog.CompletionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[catalog.CompletionConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_completion_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CatalogService server but before it is returned to user code. + + We recommend only using this `post_update_completion_config_with_metadata` + interceptor in new development instead of the `post_update_completion_config` interceptor. + When both interceptors are used, this `post_update_completion_config_with_metadata` interceptor runs after the + `post_update_completion_config` interceptor. The (possibly modified) response returned by + `post_update_completion_config` will be passed to + `post_update_completion_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -731,6 +992,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -887,6 +1152,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_remove_catalog_attributes(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_batch_remove_catalog_attributes_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1036,6 +1308,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1184,6 +1460,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1329,6 +1609,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_default_branch(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_default_branch_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1476,6 +1760,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_catalogs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_catalogs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1631,6 +1919,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1784,6 +2076,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_replace_catalog_attribute(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_replace_catalog_attribute_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2052,6 +2348,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_attributes_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_attributes_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2200,6 +2500,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_catalog(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_catalog_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2356,6 +2660,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_completion_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_completion_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/client.py index 83ab75290984..ca8f0b505f2a 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -493,6 +495,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -957,16 +986,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1012,16 +1045,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/transports/rest.py index dc74f47f8e37..22d8aba6ef90 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/completion_service/transports/rest.py @@ -111,12 +111,38 @@ def post_complete_query( ) -> completion_service.CompleteQueryResponse: """Post-rpc interceptor for complete_query - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_complete_query_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_complete_query` interceptor runs + before the `post_complete_query_with_metadata` interceptor. """ return response + def post_complete_query_with_metadata( + self, + response: completion_service.CompleteQueryResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + completion_service.CompleteQueryResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for complete_query + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_complete_query_with_metadata` + interceptor in new development instead of the `post_complete_query` interceptor. + When both interceptors are used, this `post_complete_query_with_metadata` interceptor runs after the + `post_complete_query` interceptor. The (possibly modified) response returned by + `post_complete_query` will be passed to + `post_complete_query_with_metadata`. + """ + return response, metadata + def pre_import_completion_data( self, request: import_config.ImportCompletionDataRequest, @@ -137,12 +163,35 @@ def post_import_completion_data( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_completion_data - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_completion_data_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CompletionService server but before - it is returned to user code. + it is returned to user code. This `post_import_completion_data` interceptor runs + before the `post_import_completion_data_with_metadata` interceptor. """ return response + def post_import_completion_data_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_completion_data + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CompletionService server but before it is returned to user code. + + We recommend only using this `post_import_completion_data_with_metadata` + interceptor in new development instead of the `post_import_completion_data` interceptor. + When both interceptors are used, this `post_import_completion_data_with_metadata` interceptor runs after the + `post_import_completion_data` interceptor. The (possibly modified) response returned by + `post_import_completion_data` will be passed to + `post_import_completion_data_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -463,6 +512,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_complete_query(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_complete_query_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -618,6 +671,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_completion_data(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_completion_data_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/client.py index f773fe55cae3..76b77a366134 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1360,16 +1389,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1415,16 +1448,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/transports/rest.py index 8a82c857a5ad..68acadc30c38 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/control_service/transports/rest.py @@ -132,12 +132,35 @@ def pre_create_control( def post_create_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for create_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_create_control` interceptor runs + before the `post_create_control_with_metadata` interceptor. """ return response + def post_create_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_create_control_with_metadata` + interceptor in new development instead of the `post_create_control` interceptor. + When both interceptors are used, this `post_create_control_with_metadata` interceptor runs after the + `post_create_control` interceptor. The (possibly modified) response returned by + `post_create_control` will be passed to + `post_create_control_with_metadata`. + """ + return response, metadata + def pre_delete_control( self, request: control_service.DeleteControlRequest, @@ -169,12 +192,35 @@ def pre_get_control( def post_get_control(self, response: control.Control) -> control.Control: """Post-rpc interceptor for get_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_get_control` interceptor runs + before the `post_get_control_with_metadata` interceptor. """ return response + def post_get_control_with_metadata( + self, + response: control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_get_control_with_metadata` + interceptor in new development instead of the `post_get_control` interceptor. + When both interceptors are used, this `post_get_control_with_metadata` interceptor runs after the + `post_get_control` interceptor. The (possibly modified) response returned by + `post_get_control` will be passed to + `post_get_control_with_metadata`. + """ + return response, metadata + def pre_list_controls( self, request: control_service.ListControlsRequest, @@ -194,12 +240,37 @@ def post_list_controls( ) -> control_service.ListControlsResponse: """Post-rpc interceptor for list_controls - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_controls_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_list_controls` interceptor runs + before the `post_list_controls_with_metadata` interceptor. """ return response + def post_list_controls_with_metadata( + self, + response: control_service.ListControlsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + control_service.ListControlsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_controls + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_list_controls_with_metadata` + interceptor in new development instead of the `post_list_controls` interceptor. + When both interceptors are used, this `post_list_controls_with_metadata` interceptor runs after the + `post_list_controls` interceptor. The (possibly modified) response returned by + `post_list_controls` will be passed to + `post_list_controls_with_metadata`. + """ + return response, metadata + def pre_update_control( self, request: control_service.UpdateControlRequest, @@ -217,12 +288,35 @@ def pre_update_control( def post_update_control(self, response: gcr_control.Control) -> gcr_control.Control: """Post-rpc interceptor for update_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ControlService server but before - it is returned to user code. + it is returned to user code. This `post_update_control` interceptor runs + before the `post_update_control_with_metadata` interceptor. """ return response + def post_update_control_with_metadata( + self, + response: gcr_control.Control, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_control.Control, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ControlService server but before it is returned to user code. + + We recommend only using this `post_update_control_with_metadata` + interceptor in new development instead of the `post_update_control` interceptor. + When both interceptors are used, this `post_update_control_with_metadata` interceptor runs after the + `post_update_control` interceptor. The (possibly modified) response returned by + `post_update_control` will be passed to + `post_update_control_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -487,6 +581,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -739,6 +837,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -879,6 +981,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_controls(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_controls_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1031,6 +1137,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/client.py index 70a438763916..68fe63e0fb5e 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -494,6 +496,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1414,16 +1443,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1469,16 +1502,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/transports/rest.py index 878b621861d1..a59cd7ff13c1 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/generative_question_service/transports/rest.py @@ -140,12 +140,38 @@ def post_batch_update_generative_question_configs( ) -> generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse: """Post-rpc interceptor for batch_update_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_batch_update_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_batch_update_generative_question_configs` interceptor runs + before the `post_batch_update_generative_question_configs_with_metadata` interceptor. """ return response + def post_batch_update_generative_question_configs_with_metadata( + self, + response: generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for batch_update_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_batch_update_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_batch_update_generative_question_configs` interceptor. + When both interceptors are used, this `post_batch_update_generative_question_configs_with_metadata` interceptor runs after the + `post_batch_update_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_batch_update_generative_question_configs` will be passed to + `post_batch_update_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_get_generative_questions_feature_config( self, request: generative_question_service.GetGenerativeQuestionsFeatureConfigRequest, @@ -166,12 +192,38 @@ def post_get_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for get_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_get_generative_questions_feature_config` interceptor runs + before the `post_get_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_get_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for get_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_get_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_get_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_get_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_get_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_get_generative_questions_feature_config` will be passed to + `post_get_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_list_generative_question_configs( self, request: generative_question_service.ListGenerativeQuestionConfigsRequest, @@ -193,12 +245,38 @@ def post_list_generative_question_configs( ) -> generative_question_service.ListGenerativeQuestionConfigsResponse: """Post-rpc interceptor for list_generative_question_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_generative_question_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_list_generative_question_configs` interceptor runs + before the `post_list_generative_question_configs_with_metadata` interceptor. """ return response + def post_list_generative_question_configs_with_metadata( + self, + response: generative_question_service.ListGenerativeQuestionConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question_service.ListGenerativeQuestionConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_generative_question_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_list_generative_question_configs_with_metadata` + interceptor in new development instead of the `post_list_generative_question_configs` interceptor. + When both interceptors are used, this `post_list_generative_question_configs_with_metadata` interceptor runs after the + `post_list_generative_question_configs` interceptor. The (possibly modified) response returned by + `post_list_generative_question_configs` will be passed to + `post_list_generative_question_configs_with_metadata`. + """ + return response, metadata + def pre_update_generative_question_config( self, request: generative_question_service.UpdateGenerativeQuestionConfigRequest, @@ -219,12 +297,38 @@ def post_update_generative_question_config( ) -> generative_question.GenerativeQuestionConfig: """Post-rpc interceptor for update_generative_question_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_question_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_question_config` interceptor runs + before the `post_update_generative_question_config_with_metadata` interceptor. """ return response + def post_update_generative_question_config_with_metadata( + self, + response: generative_question.GenerativeQuestionConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_question_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_question_config_with_metadata` + interceptor in new development instead of the `post_update_generative_question_config` interceptor. + When both interceptors are used, this `post_update_generative_question_config_with_metadata` interceptor runs after the + `post_update_generative_question_config` interceptor. The (possibly modified) response returned by + `post_update_generative_question_config` will be passed to + `post_update_generative_question_config_with_metadata`. + """ + return response, metadata + def pre_update_generative_questions_feature_config( self, request: generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest, @@ -245,12 +349,38 @@ def post_update_generative_questions_feature_config( ) -> generative_question.GenerativeQuestionsFeatureConfig: """Post-rpc interceptor for update_generative_questions_feature_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_generative_questions_feature_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the GenerativeQuestionService server but before - it is returned to user code. + it is returned to user code. This `post_update_generative_questions_feature_config` interceptor runs + before the `post_update_generative_questions_feature_config_with_metadata` interceptor. """ return response + def post_update_generative_questions_feature_config_with_metadata( + self, + response: generative_question.GenerativeQuestionsFeatureConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + generative_question.GenerativeQuestionsFeatureConfig, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for update_generative_questions_feature_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the GenerativeQuestionService server but before it is returned to user code. + + We recommend only using this `post_update_generative_questions_feature_config_with_metadata` + interceptor in new development instead of the `post_update_generative_questions_feature_config` interceptor. + When both interceptors are used, this `post_update_generative_questions_feature_config_with_metadata` interceptor runs after the + `post_update_generative_questions_feature_config` interceptor. The (possibly modified) response returned by + `post_update_generative_questions_feature_config` will be passed to + `post_update_generative_questions_feature_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -531,6 +661,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_batch_update_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_batch_update_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -686,6 +823,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_generative_questions_feature_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_get_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -840,6 +984,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_generative_question_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_list_generative_question_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -997,6 +1148,13 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_generative_question_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_question_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1160,6 +1318,13 @@ def __call__( resp = self._interceptor.post_update_generative_questions_feature_config( resp ) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + ( + resp, + _, + ) = self._interceptor.post_update_generative_questions_feature_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/client.py index ecf7cc01c869..9f9040d082c6 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -528,6 +530,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1711,16 +1740,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1766,16 +1799,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/transports/rest.py index 065b6dabc914..165bf385c3a5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/model_service/transports/rest.py @@ -158,12 +158,35 @@ def post_create_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for create_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_create_model` interceptor runs + before the `post_create_model_with_metadata` interceptor. """ return response + def post_create_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_create_model_with_metadata` + interceptor in new development instead of the `post_create_model` interceptor. + When both interceptors are used, this `post_create_model_with_metadata` interceptor runs after the + `post_create_model` interceptor. The (possibly modified) response returned by + `post_create_model` will be passed to + `post_create_model_with_metadata`. + """ + return response, metadata + def pre_delete_model( self, request: model_service.DeleteModelRequest, @@ -193,12 +216,33 @@ def pre_get_model( def post_get_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for get_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_get_model` interceptor runs + before the `post_get_model_with_metadata` interceptor. """ return response + def post_get_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_get_model_with_metadata` + interceptor in new development instead of the `post_get_model` interceptor. + When both interceptors are used, this `post_get_model_with_metadata` interceptor runs after the + `post_get_model` interceptor. The (possibly modified) response returned by + `post_get_model` will be passed to + `post_get_model_with_metadata`. + """ + return response, metadata + def pre_list_models( self, request: model_service.ListModelsRequest, @@ -218,12 +262,37 @@ def post_list_models( ) -> model_service.ListModelsResponse: """Post-rpc interceptor for list_models - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_models_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_list_models` interceptor runs + before the `post_list_models_with_metadata` interceptor. """ return response + def post_list_models_with_metadata( + self, + response: model_service.ListModelsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + model_service.ListModelsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_models + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_list_models_with_metadata` + interceptor in new development instead of the `post_list_models` interceptor. + When both interceptors are used, this `post_list_models_with_metadata` interceptor runs after the + `post_list_models` interceptor. The (possibly modified) response returned by + `post_list_models` will be passed to + `post_list_models_with_metadata`. + """ + return response, metadata + def pre_pause_model( self, request: model_service.PauseModelRequest, @@ -241,12 +310,33 @@ def pre_pause_model( def post_pause_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for pause_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_pause_model` interceptor runs + before the `post_pause_model_with_metadata` interceptor. """ return response + def post_pause_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_pause_model_with_metadata` + interceptor in new development instead of the `post_pause_model` interceptor. + When both interceptors are used, this `post_pause_model_with_metadata` interceptor runs after the + `post_pause_model` interceptor. The (possibly modified) response returned by + `post_pause_model` will be passed to + `post_pause_model_with_metadata`. + """ + return response, metadata + def pre_resume_model( self, request: model_service.ResumeModelRequest, @@ -264,12 +354,33 @@ def pre_resume_model( def post_resume_model(self, response: model.Model) -> model.Model: """Post-rpc interceptor for resume_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_resume_model` interceptor runs + before the `post_resume_model_with_metadata` interceptor. """ return response + def post_resume_model_with_metadata( + self, response: model.Model, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_resume_model_with_metadata` + interceptor in new development instead of the `post_resume_model` interceptor. + When both interceptors are used, this `post_resume_model_with_metadata` interceptor runs after the + `post_resume_model` interceptor. The (possibly modified) response returned by + `post_resume_model` will be passed to + `post_resume_model_with_metadata`. + """ + return response, metadata + def pre_tune_model( self, request: model_service.TuneModelRequest, @@ -287,12 +398,35 @@ def post_tune_model( ) -> operations_pb2.Operation: """Post-rpc interceptor for tune_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_tune_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_tune_model` interceptor runs + before the `post_tune_model_with_metadata` interceptor. """ return response + def post_tune_model_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for tune_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_tune_model_with_metadata` + interceptor in new development instead of the `post_tune_model` interceptor. + When both interceptors are used, this `post_tune_model_with_metadata` interceptor runs after the + `post_tune_model` interceptor. The (possibly modified) response returned by + `post_tune_model` will be passed to + `post_tune_model_with_metadata`. + """ + return response, metadata + def pre_update_model( self, request: model_service.UpdateModelRequest, @@ -310,12 +444,35 @@ def pre_update_model( def post_update_model(self, response: gcr_model.Model) -> gcr_model.Model: """Post-rpc interceptor for update_model - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_model_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ModelService server but before - it is returned to user code. + it is returned to user code. This `post_update_model` interceptor runs + before the `post_update_model_with_metadata` interceptor. """ return response + def post_update_model_with_metadata( + self, + response: gcr_model.Model, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_model.Model, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_model + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ModelService server but before it is returned to user code. + + We recommend only using this `post_update_model_with_metadata` + interceptor in new development instead of the `post_update_model` interceptor. + When both interceptors are used, this `post_update_model_with_metadata` interceptor runs after the + `post_update_model` interceptor. The (possibly modified) response returned by + `post_update_model` will be passed to + `post_update_model_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -655,6 +812,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -914,6 +1075,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1059,6 +1224,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_models(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_models_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1221,6 +1390,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1381,6 +1554,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1535,6 +1712,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_tune_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_tune_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1695,6 +1876,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_model(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_model_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/client.py index fcc284016dea..80b736344d59 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -490,6 +492,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -836,16 +865,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -891,16 +924,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/transports/rest.py index b41e60438074..6d6dc7d1afb9 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/prediction_service/transports/rest.py @@ -103,12 +103,37 @@ def post_predict( ) -> prediction_service.PredictResponse: """Post-rpc interceptor for predict - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_predict_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the PredictionService server but before - it is returned to user code. + it is returned to user code. This `post_predict` interceptor runs + before the `post_predict_with_metadata` interceptor. """ return response + def post_predict_with_metadata( + self, + response: prediction_service.PredictResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + prediction_service.PredictResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for predict + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the PredictionService server but before it is returned to user code. + + We recommend only using this `post_predict_with_metadata` + interceptor in new development instead of the `post_predict` interceptor. + When both interceptors are used, this `post_predict_with_metadata` interceptor runs after the + `post_predict` interceptor. The (possibly modified) response returned by + `post_predict` will be passed to + `post_predict_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -373,6 +398,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_predict(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_predict_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/client.py index e4c3e6ec1277..64f15472e1a6 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -526,6 +528,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -2680,16 +2709,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -2735,16 +2768,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/transports/rest.py index b925132e9dbd..a263da1f7e18 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/product_service/transports/rest.py @@ -200,12 +200,35 @@ def post_add_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_fulfillment_places` interceptor runs + before the `post_add_fulfillment_places_with_metadata` interceptor. """ return response + def post_add_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_add_fulfillment_places` interceptor. + When both interceptors are used, this `post_add_fulfillment_places_with_metadata` interceptor runs after the + `post_add_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_add_fulfillment_places` will be passed to + `post_add_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_add_local_inventories( self, request: product_service.AddLocalInventoriesRequest, @@ -226,12 +249,35 @@ def post_add_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for add_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_add_local_inventories` interceptor runs + before the `post_add_local_inventories_with_metadata` interceptor. """ return response + def post_add_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for add_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_add_local_inventories_with_metadata` + interceptor in new development instead of the `post_add_local_inventories` interceptor. + When both interceptors are used, this `post_add_local_inventories_with_metadata` interceptor runs after the + `post_add_local_inventories` interceptor. The (possibly modified) response returned by + `post_add_local_inventories` will be passed to + `post_add_local_inventories_with_metadata`. + """ + return response, metadata + def pre_create_product( self, request: product_service.CreateProductRequest, @@ -249,12 +295,35 @@ def pre_create_product( def post_create_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for create_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_create_product` interceptor runs + before the `post_create_product_with_metadata` interceptor. """ return response + def post_create_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_create_product_with_metadata` + interceptor in new development instead of the `post_create_product` interceptor. + When both interceptors are used, this `post_create_product_with_metadata` interceptor runs after the + `post_create_product` interceptor. The (possibly modified) response returned by + `post_create_product` will be passed to + `post_create_product_with_metadata`. + """ + return response, metadata + def pre_delete_product( self, request: product_service.DeleteProductRequest, @@ -288,12 +357,35 @@ def post_export_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_export_products` interceptor runs + before the `post_export_products_with_metadata` interceptor. """ return response + def post_export_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_export_products_with_metadata` + interceptor in new development instead of the `post_export_products` interceptor. + When both interceptors are used, this `post_export_products_with_metadata` interceptor runs after the + `post_export_products` interceptor. The (possibly modified) response returned by + `post_export_products` will be passed to + `post_export_products_with_metadata`. + """ + return response, metadata + def pre_get_product( self, request: product_service.GetProductRequest, @@ -311,12 +403,35 @@ def pre_get_product( def post_get_product(self, response: product.Product) -> product.Product: """Post-rpc interceptor for get_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_get_product` interceptor runs + before the `post_get_product_with_metadata` interceptor. """ return response + def post_get_product_with_metadata( + self, + response: product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_get_product_with_metadata` + interceptor in new development instead of the `post_get_product` interceptor. + When both interceptors are used, this `post_get_product_with_metadata` interceptor runs after the + `post_get_product` interceptor. The (possibly modified) response returned by + `post_get_product` will be passed to + `post_get_product_with_metadata`. + """ + return response, metadata + def pre_import_products( self, request: import_config.ImportProductsRequest, @@ -336,12 +451,35 @@ def post_import_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_import_products` interceptor runs + before the `post_import_products_with_metadata` interceptor. """ return response + def post_import_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_import_products_with_metadata` + interceptor in new development instead of the `post_import_products` interceptor. + When both interceptors are used, this `post_import_products_with_metadata` interceptor runs after the + `post_import_products` interceptor. The (possibly modified) response returned by + `post_import_products` will be passed to + `post_import_products_with_metadata`. + """ + return response, metadata + def pre_list_products( self, request: product_service.ListProductsRequest, @@ -361,12 +499,37 @@ def post_list_products( ) -> product_service.ListProductsResponse: """Post-rpc interceptor for list_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_list_products` interceptor runs + before the `post_list_products_with_metadata` interceptor. """ return response + def post_list_products_with_metadata( + self, + response: product_service.ListProductsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + product_service.ListProductsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_list_products_with_metadata` + interceptor in new development instead of the `post_list_products` interceptor. + When both interceptors are used, this `post_list_products_with_metadata` interceptor runs after the + `post_list_products` interceptor. The (possibly modified) response returned by + `post_list_products` will be passed to + `post_list_products_with_metadata`. + """ + return response, metadata + def pre_purge_products( self, request: purge_config.PurgeProductsRequest, @@ -386,12 +549,35 @@ def post_purge_products( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_products - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_products_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_purge_products` interceptor runs + before the `post_purge_products_with_metadata` interceptor. """ return response + def post_purge_products_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_products + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_purge_products_with_metadata` + interceptor in new development instead of the `post_purge_products` interceptor. + When both interceptors are used, this `post_purge_products_with_metadata` interceptor runs after the + `post_purge_products` interceptor. The (possibly modified) response returned by + `post_purge_products` will be passed to + `post_purge_products_with_metadata`. + """ + return response, metadata + def pre_remove_fulfillment_places( self, request: product_service.RemoveFulfillmentPlacesRequest, @@ -412,12 +598,35 @@ def post_remove_fulfillment_places( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_fulfillment_places - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_fulfillment_places_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_fulfillment_places` interceptor runs + before the `post_remove_fulfillment_places_with_metadata` interceptor. """ return response + def post_remove_fulfillment_places_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_fulfillment_places + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_fulfillment_places_with_metadata` + interceptor in new development instead of the `post_remove_fulfillment_places` interceptor. + When both interceptors are used, this `post_remove_fulfillment_places_with_metadata` interceptor runs after the + `post_remove_fulfillment_places` interceptor. The (possibly modified) response returned by + `post_remove_fulfillment_places` will be passed to + `post_remove_fulfillment_places_with_metadata`. + """ + return response, metadata + def pre_remove_local_inventories( self, request: product_service.RemoveLocalInventoriesRequest, @@ -438,12 +647,35 @@ def post_remove_local_inventories( ) -> operations_pb2.Operation: """Post-rpc interceptor for remove_local_inventories - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_local_inventories_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_remove_local_inventories` interceptor runs + before the `post_remove_local_inventories_with_metadata` interceptor. """ return response + def post_remove_local_inventories_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for remove_local_inventories + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_remove_local_inventories_with_metadata` + interceptor in new development instead of the `post_remove_local_inventories` interceptor. + When both interceptors are used, this `post_remove_local_inventories_with_metadata` interceptor runs after the + `post_remove_local_inventories` interceptor. The (possibly modified) response returned by + `post_remove_local_inventories` will be passed to + `post_remove_local_inventories_with_metadata`. + """ + return response, metadata + def pre_set_inventory( self, request: product_service.SetInventoryRequest, @@ -463,12 +695,35 @@ def post_set_inventory( ) -> operations_pb2.Operation: """Post-rpc interceptor for set_inventory - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_set_inventory_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_set_inventory` interceptor runs + before the `post_set_inventory_with_metadata` interceptor. """ return response + def post_set_inventory_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for set_inventory + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_set_inventory_with_metadata` + interceptor in new development instead of the `post_set_inventory` interceptor. + When both interceptors are used, this `post_set_inventory_with_metadata` interceptor runs after the + `post_set_inventory` interceptor. The (possibly modified) response returned by + `post_set_inventory` will be passed to + `post_set_inventory_with_metadata`. + """ + return response, metadata + def pre_update_product( self, request: product_service.UpdateProductRequest, @@ -486,12 +741,35 @@ def pre_update_product( def post_update_product(self, response: gcr_product.Product) -> gcr_product.Product: """Post-rpc interceptor for update_product - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_product_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProductService server but before - it is returned to user code. + it is returned to user code. This `post_update_product` interceptor runs + before the `post_update_product_with_metadata` interceptor. """ return response + def post_update_product_with_metadata( + self, + response: gcr_product.Product, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[gcr_product.Product, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_product + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProductService server but before it is returned to user code. + + We recommend only using this `post_update_product_with_metadata` + interceptor in new development instead of the `post_update_product` interceptor. + When both interceptors are used, this `post_update_product_with_metadata` interceptor runs after the + `post_update_product` interceptor. The (possibly modified) response returned by + `post_update_product` will be passed to + `post_update_product_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -820,6 +1098,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -972,6 +1254,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1123,6 +1409,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1379,6 +1669,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1526,6 +1820,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1673,6 +1971,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1818,6 +2120,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1968,6 +2274,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_products(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_products_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2122,6 +2432,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_fulfillment_places(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_fulfillment_places_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2276,6 +2590,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_local_inventories(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_local_inventories_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2425,6 +2743,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_set_inventory(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_set_inventory_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -2576,6 +2898,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_product(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_product_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/client.py index 3a6632933a62..90cd29f3503f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -480,6 +482,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -967,16 +996,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1022,16 +1055,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/transports/rest.py index 343e3e460ad0..c01487640bc3 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/project_service/transports/rest.py @@ -111,12 +111,35 @@ def post_get_alert_config( ) -> project.AlertConfig: """Post-rpc interceptor for get_alert_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_alert_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_get_alert_config` interceptor runs + before the `post_get_alert_config_with_metadata` interceptor. """ return response + def post_get_alert_config_with_metadata( + self, + response: project.AlertConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.AlertConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_alert_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_get_alert_config_with_metadata` + interceptor in new development instead of the `post_get_alert_config` interceptor. + When both interceptors are used, this `post_get_alert_config_with_metadata` interceptor runs after the + `post_get_alert_config` interceptor. The (possibly modified) response returned by + `post_get_alert_config` will be passed to + `post_get_alert_config_with_metadata`. + """ + return response, metadata + def pre_update_alert_config( self, request: project_service.UpdateAlertConfigRequest, @@ -137,12 +160,35 @@ def post_update_alert_config( ) -> project.AlertConfig: """Post-rpc interceptor for update_alert_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_alert_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ProjectService server but before - it is returned to user code. + it is returned to user code. This `post_update_alert_config` interceptor runs + before the `post_update_alert_config_with_metadata` interceptor. """ return response + def post_update_alert_config_with_metadata( + self, + response: project.AlertConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[project.AlertConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_alert_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ProjectService server but before it is returned to user code. + + We recommend only using this `post_update_alert_config_with_metadata` + interceptor in new development instead of the `post_update_alert_config` interceptor. + When both interceptors are used, this `post_update_alert_config_with_metadata` interceptor runs after the + `post_update_alert_config` interceptor. The (possibly modified) response returned by + `post_update_alert_config` will be passed to + `post_update_alert_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -401,6 +447,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_alert_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_alert_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -551,6 +601,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_alert_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_alert_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/client.py index 62061fae74aa..219d8e8f802f 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -566,6 +568,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -927,16 +956,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -982,16 +1015,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/transports/rest.py index df0ec4af6eb2..ecc0da0fbd15 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/search_service/transports/rest.py @@ -101,12 +101,35 @@ def post_search( ) -> search_service.SearchResponse: """Post-rpc interceptor for search - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_search_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the SearchService server but before - it is returned to user code. + it is returned to user code. This `post_search` interceptor runs + before the `post_search_with_metadata` interceptor. """ return response + def post_search_with_metadata( + self, + response: search_service.SearchResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[search_service.SearchResponse, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for search + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the SearchService server but before it is returned to user code. + + We recommend only using this `post_search_with_metadata` + interceptor in new development instead of the `post_search` interceptor. + When both interceptors are used, this `post_search_with_metadata` interceptor runs after the + `post_search` interceptor. The (possibly modified) response returned by + `post_search` will be passed to + `post_search_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -378,6 +401,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_search(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_search_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/client.py index e43a252b88ef..322427f823b5 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -515,6 +517,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1610,16 +1639,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1665,16 +1698,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/transports/rest.py index 65e41bb6991e..eb22084cb5bf 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/serving_config_service/transports/rest.py @@ -151,12 +151,37 @@ def post_add_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for add_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_add_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_add_control` interceptor runs + before the `post_add_control_with_metadata` interceptor. """ return response + def post_add_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for add_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_add_control_with_metadata` + interceptor in new development instead of the `post_add_control` interceptor. + When both interceptors are used, this `post_add_control_with_metadata` interceptor runs after the + `post_add_control` interceptor. The (possibly modified) response returned by + `post_add_control` will be passed to + `post_add_control_with_metadata`. + """ + return response, metadata + def pre_create_serving_config( self, request: serving_config_service.CreateServingConfigRequest, @@ -177,12 +202,37 @@ def post_create_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for create_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_create_serving_config` interceptor runs + before the `post_create_serving_config_with_metadata` interceptor. """ return response + def post_create_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for create_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_create_serving_config_with_metadata` + interceptor in new development instead of the `post_create_serving_config` interceptor. + When both interceptors are used, this `post_create_serving_config_with_metadata` interceptor runs after the + `post_create_serving_config` interceptor. The (possibly modified) response returned by + `post_create_serving_config` will be passed to + `post_create_serving_config_with_metadata`. + """ + return response, metadata + def pre_delete_serving_config( self, request: serving_config_service.DeleteServingConfigRequest, @@ -218,12 +268,35 @@ def post_get_serving_config( ) -> serving_config.ServingConfig: """Post-rpc interceptor for get_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_get_serving_config` interceptor runs + before the `post_get_serving_config_with_metadata` interceptor. """ return response + def post_get_serving_config_with_metadata( + self, + response: serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_get_serving_config_with_metadata` + interceptor in new development instead of the `post_get_serving_config` interceptor. + When both interceptors are used, this `post_get_serving_config_with_metadata` interceptor runs after the + `post_get_serving_config` interceptor. The (possibly modified) response returned by + `post_get_serving_config` will be passed to + `post_get_serving_config_with_metadata`. + """ + return response, metadata + def pre_list_serving_configs( self, request: serving_config_service.ListServingConfigsRequest, @@ -244,12 +317,38 @@ def post_list_serving_configs( ) -> serving_config_service.ListServingConfigsResponse: """Post-rpc interceptor for list_serving_configs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_serving_configs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_list_serving_configs` interceptor runs + before the `post_list_serving_configs_with_metadata` interceptor. """ return response + def post_list_serving_configs_with_metadata( + self, + response: serving_config_service.ListServingConfigsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + serving_config_service.ListServingConfigsResponse, + Sequence[Tuple[str, Union[str, bytes]]], + ]: + """Post-rpc interceptor for list_serving_configs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_list_serving_configs_with_metadata` + interceptor in new development instead of the `post_list_serving_configs` interceptor. + When both interceptors are used, this `post_list_serving_configs_with_metadata` interceptor runs after the + `post_list_serving_configs` interceptor. The (possibly modified) response returned by + `post_list_serving_configs` will be passed to + `post_list_serving_configs_with_metadata`. + """ + return response, metadata + def pre_remove_control( self, request: serving_config_service.RemoveControlRequest, @@ -270,12 +369,37 @@ def post_remove_control( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for remove_control - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_remove_control_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_remove_control` interceptor runs + before the `post_remove_control_with_metadata` interceptor. """ return response + def post_remove_control_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for remove_control + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_remove_control_with_metadata` + interceptor in new development instead of the `post_remove_control` interceptor. + When both interceptors are used, this `post_remove_control_with_metadata` interceptor runs after the + `post_remove_control` interceptor. The (possibly modified) response returned by + `post_remove_control` will be passed to + `post_remove_control_with_metadata`. + """ + return response, metadata + def pre_update_serving_config( self, request: serving_config_service.UpdateServingConfigRequest, @@ -296,12 +420,37 @@ def post_update_serving_config( ) -> gcr_serving_config.ServingConfig: """Post-rpc interceptor for update_serving_config - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_serving_config_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the ServingConfigService server but before - it is returned to user code. + it is returned to user code. This `post_update_serving_config` interceptor runs + before the `post_update_serving_config_with_metadata` interceptor. """ return response + def post_update_serving_config_with_metadata( + self, + response: gcr_serving_config.ServingConfig, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + gcr_serving_config.ServingConfig, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for update_serving_config + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the ServingConfigService server but before it is returned to user code. + + We recommend only using this `post_update_serving_config_with_metadata` + interceptor in new development instead of the `post_update_serving_config` interceptor. + When both interceptors are used, this `post_update_serving_config_with_metadata` interceptor runs after the + `post_update_serving_config` interceptor. The (possibly modified) response returned by + `post_update_serving_config` will be passed to + `post_update_serving_config_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -567,6 +716,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_add_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_add_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -725,6 +878,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -988,6 +1145,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1136,6 +1297,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_serving_configs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_serving_configs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1291,6 +1456,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_remove_control(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_remove_control_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1449,6 +1618,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_serving_config(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_serving_config_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/client.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/client.py index 4fe0c29624ee..5fef051f0afd 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/client.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -526,6 +528,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1445,16 +1474,20 @@ def list_operations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def get_operation( self, @@ -1500,16 +1533,20 @@ def get_operation( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/transports/rest.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/transports/rest.py index 2d4e90077575..86f52fd4e3ad 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/transports/rest.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/services/user_event_service/transports/rest.py @@ -151,12 +151,35 @@ def post_collect_user_event( ) -> httpbody_pb2.HttpBody: """Post-rpc interceptor for collect_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_collect_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_collect_user_event` interceptor runs + before the `post_collect_user_event_with_metadata` interceptor. """ return response + def post_collect_user_event_with_metadata( + self, + response: httpbody_pb2.HttpBody, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[httpbody_pb2.HttpBody, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for collect_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_collect_user_event_with_metadata` + interceptor in new development instead of the `post_collect_user_event` interceptor. + When both interceptors are used, this `post_collect_user_event_with_metadata` interceptor runs after the + `post_collect_user_event` interceptor. The (possibly modified) response returned by + `post_collect_user_event` will be passed to + `post_collect_user_event_with_metadata`. + """ + return response, metadata + def pre_export_user_events( self, request: export_config.ExportUserEventsRequest, @@ -176,12 +199,35 @@ def post_export_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for export_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_export_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_export_user_events` interceptor runs + before the `post_export_user_events_with_metadata` interceptor. """ return response + def post_export_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for export_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_export_user_events_with_metadata` + interceptor in new development instead of the `post_export_user_events` interceptor. + When both interceptors are used, this `post_export_user_events_with_metadata` interceptor runs after the + `post_export_user_events` interceptor. The (possibly modified) response returned by + `post_export_user_events` will be passed to + `post_export_user_events_with_metadata`. + """ + return response, metadata + def pre_import_user_events( self, request: import_config.ImportUserEventsRequest, @@ -201,12 +247,35 @@ def post_import_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for import_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_import_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_import_user_events` interceptor runs + before the `post_import_user_events_with_metadata` interceptor. """ return response + def post_import_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for import_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_import_user_events_with_metadata` + interceptor in new development instead of the `post_import_user_events` interceptor. + When both interceptors are used, this `post_import_user_events_with_metadata` interceptor runs after the + `post_import_user_events` interceptor. The (possibly modified) response returned by + `post_import_user_events` will be passed to + `post_import_user_events_with_metadata`. + """ + return response, metadata + def pre_purge_user_events( self, request: purge_config.PurgeUserEventsRequest, @@ -226,12 +295,35 @@ def post_purge_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for purge_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_purge_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_purge_user_events` interceptor runs + before the `post_purge_user_events_with_metadata` interceptor. """ return response + def post_purge_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for purge_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_purge_user_events_with_metadata` + interceptor in new development instead of the `post_purge_user_events` interceptor. + When both interceptors are used, this `post_purge_user_events_with_metadata` interceptor runs after the + `post_purge_user_events` interceptor. The (possibly modified) response returned by + `post_purge_user_events` will be passed to + `post_purge_user_events_with_metadata`. + """ + return response, metadata + def pre_rejoin_user_events( self, request: user_event_service.RejoinUserEventsRequest, @@ -252,12 +344,35 @@ def post_rejoin_user_events( ) -> operations_pb2.Operation: """Post-rpc interceptor for rejoin_user_events - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_rejoin_user_events_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_rejoin_user_events` interceptor runs + before the `post_rejoin_user_events_with_metadata` interceptor. """ return response + def post_rejoin_user_events_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for rejoin_user_events + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_rejoin_user_events_with_metadata` + interceptor in new development instead of the `post_rejoin_user_events` interceptor. + When both interceptors are used, this `post_rejoin_user_events_with_metadata` interceptor runs after the + `post_rejoin_user_events` interceptor. The (possibly modified) response returned by + `post_rejoin_user_events` will be passed to + `post_rejoin_user_events_with_metadata`. + """ + return response, metadata + def pre_write_user_event( self, request: user_event_service.WriteUserEventRequest, @@ -278,12 +393,35 @@ def post_write_user_event( ) -> user_event.UserEvent: """Post-rpc interceptor for write_user_event - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_write_user_event_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the UserEventService server but before - it is returned to user code. + it is returned to user code. This `post_write_user_event` interceptor runs + before the `post_write_user_event_with_metadata` interceptor. """ return response + def post_write_user_event_with_metadata( + self, + response: user_event.UserEvent, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[user_event.UserEvent, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for write_user_event + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the UserEventService server but before it is returned to user code. + + We recommend only using this `post_write_user_event_with_metadata` + interceptor in new development instead of the `post_write_user_event` interceptor. + When both interceptors are used, this `post_write_user_event_with_metadata` interceptor runs after the + `post_write_user_event` interceptor. The (possibly modified) response returned by + `post_write_user_event` will be passed to + `post_write_user_event_with_metadata`. + """ + return response, metadata + def pre_get_operation( self, request: operations_pb2.GetOperationRequest, @@ -653,6 +791,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_collect_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_collect_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -803,6 +945,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_export_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_export_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -954,6 +1100,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_import_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_import_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1105,6 +1255,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_purge_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_purge_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1256,6 +1410,10 @@ def __call__( json_format.Parse(response.content, resp, ignore_unknown_fields=True) resp = self._interceptor.post_rejoin_user_events(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_rejoin_user_events_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1409,6 +1567,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_write_user_event(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_write_user_event_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-retail/noxfile.py b/packages/google-cloud-retail/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-retail/noxfile.py +++ b/packages/google-cloud-retail/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json index dd51ee1f31fe..2551a0da71ff 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "1.24.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json index f724e57f7bcb..b27771e5b373 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "1.24.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json index cffd5e7c17c4..5b91d0f376d7 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "1.24.0" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_analytics_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_analytics_service.py index 5baf13a7c3b6..f28c3a7eda09 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_analytics_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_analytics_service.py @@ -70,6 +70,13 @@ ) from google.cloud.retail_v2.types import export_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -329,6 +336,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,14 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ), mock.patch.object( transports.AnalyticsServiceRestInterceptor, "post_export_analytics_metrics" ) as post, mock.patch.object( + transports.AnalyticsServiceRestInterceptor, + "post_export_analytics_metrics_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AnalyticsServiceRestInterceptor, "pre_export_analytics_metrics" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportAnalyticsMetricsRequest.pb( export_config.ExportAnalyticsMetricsRequest() ) @@ -1780,6 +1834,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_analytics_metrics( request, @@ -1791,6 +1846,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_catalog_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_catalog_service.py index ae85f9bb43bd..223c839b6c06 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_catalog_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_catalog_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2.types import catalog as gcr_catalog from google.cloud.retail_v2.types import catalog_service, common, import_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7467,10 +7517,13 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_list_catalogs" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_list_catalogs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_list_catalogs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ListCatalogsRequest.pb( catalog_service.ListCatalogsRequest() ) @@ -7496,6 +7549,10 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.ListCatalogsResponse() + post_with_metadata.return_value = ( + catalog_service.ListCatalogsResponse(), + metadata, + ) client.list_catalogs( request, @@ -7507,6 +7564,7 @@ def test_list_catalogs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_catalog_rest_bad_request( @@ -7672,10 +7730,13 @@ def test_update_catalog_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_catalog" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_update_catalog_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_catalog" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCatalogRequest.pb( catalog_service.UpdateCatalogRequest() ) @@ -7699,6 +7760,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_catalog.Catalog() + post_with_metadata.return_value = gcr_catalog.Catalog(), metadata client.update_catalog( request, @@ -7710,6 +7772,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_default_branch_rest_bad_request( @@ -7905,10 +7968,14 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_default_branch" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_default_branch_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_default_branch" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetDefaultBranchRequest.pb( catalog_service.GetDefaultBranchRequest() ) @@ -7934,6 +8001,10 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.GetDefaultBranchResponse() + post_with_metadata.return_value = ( + catalog_service.GetDefaultBranchResponse(), + metadata, + ) client.get_default_branch( request, @@ -7945,6 +8016,7 @@ def test_get_default_branch_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_completion_config_rest_bad_request( @@ -8056,10 +8128,14 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetCompletionConfigRequest.pb( catalog_service.GetCompletionConfigRequest() ) @@ -8083,6 +8159,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.get_completion_config( request, @@ -8094,6 +8171,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_completion_config_rest_bad_request( @@ -8300,10 +8378,14 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCompletionConfigRequest.pb( catalog_service.UpdateCompletionConfigRequest() ) @@ -8327,6 +8409,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.update_completion_config( request, @@ -8338,6 +8421,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_attributes_config_rest_bad_request( @@ -8431,10 +8515,14 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetAttributesConfigRequest.pb( catalog_service.GetAttributesConfigRequest() ) @@ -8458,6 +8546,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.get_attributes_config( request, @@ -8469,6 +8558,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_attributes_config_rest_bad_request( @@ -8640,10 +8730,14 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateAttributesConfigRequest.pb( catalog_service.UpdateAttributesConfigRequest() ) @@ -8667,6 +8761,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.update_attributes_config( request, @@ -8678,6 +8773,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_catalog_attribute_rest_bad_request( @@ -8771,10 +8867,14 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_add_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_add_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_add_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.AddCatalogAttributeRequest.pb( catalog_service.AddCatalogAttributeRequest() ) @@ -8798,6 +8898,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.add_catalog_attribute( request, @@ -8809,6 +8910,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_catalog_attribute_rest_bad_request( @@ -8902,10 +9004,14 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_remove_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_remove_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_remove_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.RemoveCatalogAttributeRequest.pb( catalog_service.RemoveCatalogAttributeRequest() ) @@ -8929,6 +9035,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.remove_catalog_attribute( request, @@ -8940,6 +9047,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_replace_catalog_attribute_rest_bad_request( @@ -9033,10 +9141,14 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_replace_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_replace_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_replace_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ReplaceCatalogAttributeRequest.pb( catalog_service.ReplaceCatalogAttributeRequest() ) @@ -9060,6 +9172,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.replace_catalog_attribute( request, @@ -9071,6 +9184,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_completion_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_completion_service.py index 21ef16f76391..1cfea4e83fc9 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_completion_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_completion_service.py @@ -71,6 +71,13 @@ ) from google.cloud.retail_v2.types import completion_service, import_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2231,10 +2281,13 @@ def test_complete_query_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CompletionServiceRestInterceptor, "post_complete_query" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, "post_complete_query_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_complete_query" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = completion_service.CompleteQueryRequest.pb( completion_service.CompleteQueryRequest() ) @@ -2260,6 +2313,10 @@ def test_complete_query_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = completion_service.CompleteQueryResponse() + post_with_metadata.return_value = ( + completion_service.CompleteQueryResponse(), + metadata, + ) client.complete_query( request, @@ -2271,6 +2328,7 @@ def test_complete_query_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_completion_data_rest_bad_request( @@ -2351,10 +2409,14 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CompletionServiceRestInterceptor, "post_import_completion_data" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, + "post_import_completion_data_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_import_completion_data" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportCompletionDataRequest.pb( import_config.ImportCompletionDataRequest() ) @@ -2378,6 +2440,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_completion_data( request, @@ -2389,6 +2452,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_control_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_control_service.py index 14df2d37a824..5907a59cbc56 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_control_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_control_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2.types import control as gcr_control from google.cloud.retail_v2.types import control_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4609,10 +4659,13 @@ def test_create_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_create_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_create_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_create_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.CreateControlRequest.pb( control_service.CreateControlRequest() ) @@ -4636,6 +4689,7 @@ def test_create_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.create_control( request, @@ -4647,6 +4701,7 @@ def test_create_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_control_rest_bad_request( @@ -4990,10 +5045,13 @@ def test_update_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_update_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_update_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_update_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.UpdateControlRequest.pb( control_service.UpdateControlRequest() ) @@ -5017,6 +5075,7 @@ def test_update_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.update_control( request, @@ -5028,6 +5087,7 @@ def test_update_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_control_rest_bad_request(request_type=control_service.GetControlRequest): @@ -5128,10 +5188,13 @@ def test_get_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_get_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_get_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_get_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.GetControlRequest.pb( control_service.GetControlRequest() ) @@ -5155,6 +5218,7 @@ def test_get_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control.Control() + post_with_metadata.return_value = control.Control(), metadata client.get_control( request, @@ -5166,6 +5230,7 @@ def test_get_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_controls_rest_bad_request( @@ -5250,10 +5315,13 @@ def test_list_controls_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_list_controls" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_list_controls_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_list_controls" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.ListControlsRequest.pb( control_service.ListControlsRequest() ) @@ -5279,6 +5347,10 @@ def test_list_controls_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control_service.ListControlsResponse() + post_with_metadata.return_value = ( + control_service.ListControlsResponse(), + metadata, + ) client.list_controls( request, @@ -5290,6 +5362,7 @@ def test_list_controls_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_generative_question_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_generative_question_service.py index 2c36de851632..a38bfb561d12 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_generative_question_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_generative_question_service.py @@ -65,6 +65,13 @@ generative_question_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -344,6 +351,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4625,11 +4675,15 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest() ) @@ -4657,6 +4711,10 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.update_generative_questions_feature_config( request, @@ -4668,6 +4726,7 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_generative_questions_feature_config_rest_bad_request( @@ -4759,11 +4818,15 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep transports.GenerativeQuestionServiceRestInterceptor, "post_get_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_get_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_get_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest() @@ -4793,6 +4856,10 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.get_generative_questions_feature_config( request, @@ -4804,6 +4871,7 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_generative_question_configs_rest_bad_request( @@ -4894,11 +4962,15 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_list_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_list_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_list_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.ListGenerativeQuestionConfigsRequest.pb( generative_question_service.ListGenerativeQuestionConfigsRequest() @@ -4930,6 +5002,10 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): post.return_value = ( generative_question_service.ListGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.ListGenerativeQuestionConfigsResponse(), + metadata, + ) client.list_generative_question_configs( request, @@ -4941,6 +5017,7 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_generative_question_config_rest_bad_request( @@ -5130,11 +5207,15 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_question_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_question_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_question_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.UpdateGenerativeQuestionConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionConfigRequest() @@ -5162,6 +5243,10 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionConfig(), + metadata, + ) client.update_generative_question_config( request, @@ -5173,6 +5258,7 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_update_generative_question_configs_rest_bad_request( @@ -5264,11 +5350,15 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce transports.GenerativeQuestionServiceRestInterceptor, "post_batch_update_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_batch_update_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_batch_update_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest.pb( generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest() ) @@ -5298,6 +5388,10 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce post.return_value = ( generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse(), + metadata, + ) client.batch_update_generative_question_configs( request, @@ -5309,6 +5403,7 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_model_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_model_service.py index 34e497c9b496..c851a7d45902 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_model_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_model_service.py @@ -76,6 +76,13 @@ from google.cloud.retail_v2.types import model as gcr_model from google.cloud.retail_v2.types import model_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6246,10 +6296,13 @@ def test_create_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_create_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_create_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_create_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.CreateModelRequest.pb( model_service.CreateModelRequest() ) @@ -6273,6 +6326,7 @@ def test_create_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_model( request, @@ -6284,6 +6338,7 @@ def test_create_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_model_rest_bad_request(request_type=model_service.GetModelRequest): @@ -6394,10 +6449,13 @@ def test_get_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_get_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_get_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_get_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.GetModelRequest.pb(model_service.GetModelRequest()) transcode.return_value = { "method": "post", @@ -6419,6 +6477,7 @@ def test_get_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.get_model( request, @@ -6430,6 +6489,7 @@ def test_get_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_pause_model_rest_bad_request(request_type=model_service.PauseModelRequest): @@ -6540,10 +6600,13 @@ def test_pause_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_pause_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_pause_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_pause_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.PauseModelRequest.pb( model_service.PauseModelRequest() ) @@ -6567,6 +6630,7 @@ def test_pause_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.pause_model( request, @@ -6578,6 +6642,7 @@ def test_pause_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_model_rest_bad_request(request_type=model_service.ResumeModelRequest): @@ -6688,10 +6753,13 @@ def test_resume_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_resume_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_resume_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_resume_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ResumeModelRequest.pb( model_service.ResumeModelRequest() ) @@ -6715,6 +6783,7 @@ def test_resume_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.resume_model( request, @@ -6726,6 +6795,7 @@ def test_resume_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_model_rest_bad_request(request_type=model_service.DeleteModelRequest): @@ -6919,10 +6989,13 @@ def test_list_models_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_list_models" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_list_models_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_list_models" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ListModelsRequest.pb( model_service.ListModelsRequest() ) @@ -6948,6 +7021,7 @@ def test_list_models_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model_service.ListModelsResponse() + post_with_metadata.return_value = model_service.ListModelsResponse(), metadata client.list_models( request, @@ -6959,6 +7033,7 @@ def test_list_models_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_model_rest_bad_request(request_type=model_service.UpdateModelRequest): @@ -7166,10 +7241,13 @@ def test_update_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_update_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_update_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_update_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.UpdateModelRequest.pb( model_service.UpdateModelRequest() ) @@ -7193,6 +7271,7 @@ def test_update_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_model.Model() + post_with_metadata.return_value = gcr_model.Model(), metadata client.update_model( request, @@ -7204,6 +7283,7 @@ def test_update_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_tune_model_rest_bad_request(request_type=model_service.TuneModelRequest): @@ -7286,10 +7366,13 @@ def test_tune_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_tune_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_tune_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_tune_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.TuneModelRequest.pb(model_service.TuneModelRequest()) transcode.return_value = { "method": "post", @@ -7311,6 +7394,7 @@ def test_tune_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.tune_model( request, @@ -7322,6 +7406,7 @@ def test_tune_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_prediction_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_prediction_service.py index 99393c91045d..f56543dc3b36 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_prediction_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_prediction_service.py @@ -72,6 +72,13 @@ user_event, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,13 @@ def test_predict_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PredictionServiceRestInterceptor, "post_predict" ) as post, mock.patch.object( + transports.PredictionServiceRestInterceptor, "post_predict_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PredictionServiceRestInterceptor, "pre_predict" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_service.PredictRequest.pb( prediction_service.PredictRequest() ) @@ -1782,6 +1835,7 @@ def test_predict_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = prediction_service.PredictResponse() + post_with_metadata.return_value = prediction_service.PredictResponse(), metadata client.predict( request, @@ -1793,6 +1847,7 @@ def test_predict_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_product_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_product_service.py index d64df1b4ae2d..eb4fc2c870ba 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_product_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_product_service.py @@ -79,6 +79,13 @@ from google.cloud.retail_v2.types import product from google.cloud.retail_v2.types import product as gcr_product +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -8624,10 +8674,13 @@ def test_create_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_create_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_create_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_create_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.CreateProductRequest.pb( product_service.CreateProductRequest() ) @@ -8651,6 +8704,7 @@ def test_create_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.create_product( request, @@ -8662,6 +8716,7 @@ def test_create_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_product_rest_bad_request(request_type=product_service.GetProductRequest): @@ -8782,10 +8837,13 @@ def test_get_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_get_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_get_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_get_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.GetProductRequest.pb( product_service.GetProductRequest() ) @@ -8809,6 +8867,7 @@ def test_get_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product.Product() + post_with_metadata.return_value = product.Product(), metadata client.get_product( request, @@ -8820,6 +8879,7 @@ def test_get_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_products_rest_bad_request( @@ -8908,10 +8968,13 @@ def test_list_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_list_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_list_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_list_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.ListProductsRequest.pb( product_service.ListProductsRequest() ) @@ -8937,6 +9000,10 @@ def test_list_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product_service.ListProductsResponse() + post_with_metadata.return_value = ( + product_service.ListProductsResponse(), + metadata, + ) client.list_products( request, @@ -8948,6 +9015,7 @@ def test_list_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_product_rest_bad_request( @@ -9221,10 +9289,13 @@ def test_update_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_update_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_update_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_update_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.UpdateProductRequest.pb( product_service.UpdateProductRequest() ) @@ -9248,6 +9319,7 @@ def test_update_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.update_product( request, @@ -9259,6 +9331,7 @@ def test_update_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_product_rest_bad_request( @@ -9456,10 +9529,13 @@ def test_purge_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_purge_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_purge_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_purge_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeProductsRequest.pb( purge_config.PurgeProductsRequest() ) @@ -9483,6 +9559,7 @@ def test_purge_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_products( request, @@ -9494,6 +9571,7 @@ def test_purge_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_products_rest_bad_request( @@ -9578,10 +9656,13 @@ def test_import_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_import_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_import_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_import_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportProductsRequest.pb( import_config.ImportProductsRequest() ) @@ -9605,6 +9686,7 @@ def test_import_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_products( request, @@ -9616,6 +9698,7 @@ def test_import_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_inventory_rest_bad_request( @@ -9704,10 +9787,13 @@ def test_set_inventory_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_set_inventory" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_set_inventory_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_set_inventory" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.SetInventoryRequest.pb( product_service.SetInventoryRequest() ) @@ -9731,6 +9817,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.set_inventory( request, @@ -9742,6 +9829,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_fulfillment_places_rest_bad_request( @@ -9826,10 +9914,14 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddFulfillmentPlacesRequest.pb( product_service.AddFulfillmentPlacesRequest() ) @@ -9853,6 +9945,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_fulfillment_places( request, @@ -9864,6 +9957,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_fulfillment_places_rest_bad_request( @@ -9948,10 +10042,14 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveFulfillmentPlacesRequest.pb( product_service.RemoveFulfillmentPlacesRequest() ) @@ -9975,6 +10073,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_fulfillment_places( request, @@ -9986,6 +10085,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_local_inventories_rest_bad_request( @@ -10070,10 +10170,14 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddLocalInventoriesRequest.pb( product_service.AddLocalInventoriesRequest() ) @@ -10097,6 +10201,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_local_inventories( request, @@ -10108,6 +10213,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_local_inventories_rest_bad_request( @@ -10192,10 +10298,14 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveLocalInventoriesRequest.pb( product_service.RemoveLocalInventoriesRequest() ) @@ -10219,6 +10329,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_local_inventories( request, @@ -10230,6 +10341,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_search_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_search_service.py index 6dbdac7f41b5..23ff7f436304 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_search_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_search_service.py @@ -62,6 +62,13 @@ ) from google.cloud.retail_v2.types import common, search_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -316,6 +323,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1999,10 +2049,13 @@ def test_search_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SearchServiceRestInterceptor, "post_search" ) as post, mock.patch.object( + transports.SearchServiceRestInterceptor, "post_search_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SearchServiceRestInterceptor, "pre_search" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = search_service.SearchRequest.pb(search_service.SearchRequest()) transcode.return_value = { "method": "post", @@ -2026,6 +2079,7 @@ def test_search_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = search_service.SearchResponse() + post_with_metadata.return_value = search_service.SearchResponse(), metadata client.search( request, @@ -2037,6 +2091,7 @@ def test_search_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_serving_config_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_serving_config_service.py index 38e9868876b4..88d0201c4810 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_serving_config_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_serving_config_service.py @@ -66,6 +66,13 @@ from google.cloud.retail_v2.types import serving_config as gcr_serving_config from google.cloud.retail_v2.types import serving_config_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6318,10 +6368,14 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_create_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_create_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_create_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.CreateServingConfigRequest.pb( serving_config_service.CreateServingConfigRequest() ) @@ -6347,6 +6401,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.create_serving_config( request, @@ -6358,6 +6413,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_serving_config_rest_bad_request( @@ -6714,10 +6770,14 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_update_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_update_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_update_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.UpdateServingConfigRequest.pb( serving_config_service.UpdateServingConfigRequest() ) @@ -6743,6 +6803,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.update_serving_config( request, @@ -6754,6 +6815,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_serving_config_rest_bad_request( @@ -6881,10 +6943,14 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_get_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_get_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_get_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.GetServingConfigRequest.pb( serving_config_service.GetServingConfigRequest() ) @@ -6910,6 +6976,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config.ServingConfig() + post_with_metadata.return_value = serving_config.ServingConfig(), metadata client.get_serving_config( request, @@ -6921,6 +6988,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_serving_configs_rest_bad_request( @@ -7007,10 +7075,14 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_list_serving_configs" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_list_serving_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_list_serving_configs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.ListServingConfigsRequest.pb( serving_config_service.ListServingConfigsRequest() ) @@ -7036,6 +7108,10 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config_service.ListServingConfigsResponse() + post_with_metadata.return_value = ( + serving_config_service.ListServingConfigsResponse(), + metadata, + ) client.list_serving_configs( request, @@ -7047,6 +7123,7 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_control_rest_bad_request( @@ -7174,10 +7251,13 @@ def test_add_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_add_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, "post_add_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_add_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.AddControlRequest.pb( serving_config_service.AddControlRequest() ) @@ -7203,6 +7283,7 @@ def test_add_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.add_control( request, @@ -7214,6 +7295,7 @@ def test_add_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_control_rest_bad_request( @@ -7341,10 +7423,14 @@ def test_remove_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_remove_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_remove_control_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_remove_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.RemoveControlRequest.pb( serving_config_service.RemoveControlRequest() ) @@ -7370,6 +7456,7 @@ def test_remove_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.remove_control( request, @@ -7381,6 +7468,7 @@ def test_remove_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_user_event_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_user_event_service.py index c3306aa0c3d1..57307927b85f 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_user_event_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2/test_user_event_service.py @@ -85,6 +85,13 @@ user_event_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -344,6 +351,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3845,10 +3895,14 @@ def test_write_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_write_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_write_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_write_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.WriteUserEventRequest.pb( user_event_service.WriteUserEventRequest() ) @@ -3872,6 +3926,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user_event.UserEvent() + post_with_metadata.return_value = user_event.UserEvent(), metadata client.write_user_event( request, @@ -3883,6 +3938,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_collect_user_event_rest_bad_request( @@ -3966,10 +4022,14 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_collect_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_collect_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_collect_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.CollectUserEventRequest.pb( user_event_service.CollectUserEventRequest() ) @@ -3993,6 +4053,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = httpbody_pb2.HttpBody() + post_with_metadata.return_value = httpbody_pb2.HttpBody(), metadata client.collect_user_event( request, @@ -4004,6 +4065,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_purge_user_events_rest_bad_request( @@ -4084,10 +4146,14 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_purge_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_purge_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_purge_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeUserEventsRequest.pb( purge_config.PurgeUserEventsRequest() ) @@ -4111,6 +4177,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_user_events( request, @@ -4122,6 +4189,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_user_events_rest_bad_request( @@ -4202,10 +4270,14 @@ def test_import_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_import_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_import_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_import_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportUserEventsRequest.pb( import_config.ImportUserEventsRequest() ) @@ -4229,6 +4301,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_user_events( request, @@ -4240,6 +4313,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_rejoin_user_events_rest_bad_request( @@ -4320,10 +4394,14 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_rejoin_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_rejoin_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_rejoin_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.RejoinUserEventsRequest.pb( user_event_service.RejoinUserEventsRequest() ) @@ -4347,6 +4425,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.rejoin_user_events( request, @@ -4358,6 +4437,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_analytics_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_analytics_service.py index b0b35e9232c7..22653f4f55bd 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_analytics_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_analytics_service.py @@ -70,6 +70,13 @@ ) from google.cloud.retail_v2alpha.types import export_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -329,6 +336,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,14 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ), mock.patch.object( transports.AnalyticsServiceRestInterceptor, "post_export_analytics_metrics" ) as post, mock.patch.object( + transports.AnalyticsServiceRestInterceptor, + "post_export_analytics_metrics_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AnalyticsServiceRestInterceptor, "pre_export_analytics_metrics" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportAnalyticsMetricsRequest.pb( export_config.ExportAnalyticsMetricsRequest() ) @@ -1780,6 +1834,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_analytics_metrics( request, @@ -1791,6 +1846,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_branch_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_branch_service.py index 7358d01b0b01..080c04a1c8a6 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_branch_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_branch_service.py @@ -62,6 +62,13 @@ ) from google.cloud.retail_v2alpha.types import branch, branch_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -316,6 +323,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = BranchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = BranchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2364,10 +2414,13 @@ def test_list_branches_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.BranchServiceRestInterceptor, "post_list_branches" ) as post, mock.patch.object( + transports.BranchServiceRestInterceptor, "post_list_branches_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.BranchServiceRestInterceptor, "pre_list_branches" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = branch_service.ListBranchesRequest.pb( branch_service.ListBranchesRequest() ) @@ -2393,6 +2446,10 @@ def test_list_branches_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = branch_service.ListBranchesResponse() + post_with_metadata.return_value = ( + branch_service.ListBranchesResponse(), + metadata, + ) client.list_branches( request, @@ -2404,6 +2461,7 @@ def test_list_branches_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_branch_rest_bad_request(request_type=branch_service.GetBranchRequest): @@ -2494,10 +2552,13 @@ def test_get_branch_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.BranchServiceRestInterceptor, "post_get_branch" ) as post, mock.patch.object( + transports.BranchServiceRestInterceptor, "post_get_branch_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.BranchServiceRestInterceptor, "pre_get_branch" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = branch_service.GetBranchRequest.pb( branch_service.GetBranchRequest() ) @@ -2521,6 +2582,7 @@ def test_get_branch_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = branch.Branch() + post_with_metadata.return_value = branch.Branch(), metadata client.get_branch( request, @@ -2532,6 +2594,7 @@ def test_get_branch_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_catalog_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_catalog_service.py index 25acb750463d..578e37aa9922 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_catalog_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_catalog_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2alpha.types import catalog from google.cloud.retail_v2alpha.types import catalog as gcr_catalog +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7924,10 +7974,13 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_list_catalogs" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_list_catalogs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_list_catalogs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ListCatalogsRequest.pb( catalog_service.ListCatalogsRequest() ) @@ -7953,6 +8006,10 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.ListCatalogsResponse() + post_with_metadata.return_value = ( + catalog_service.ListCatalogsResponse(), + metadata, + ) client.list_catalogs( request, @@ -7964,6 +8021,7 @@ def test_list_catalogs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_catalog_rest_bad_request( @@ -8146,10 +8204,13 @@ def test_update_catalog_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_catalog" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_update_catalog_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_catalog" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCatalogRequest.pb( catalog_service.UpdateCatalogRequest() ) @@ -8173,6 +8234,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_catalog.Catalog() + post_with_metadata.return_value = gcr_catalog.Catalog(), metadata client.update_catalog( request, @@ -8184,6 +8246,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_default_branch_rest_bad_request( @@ -8379,10 +8442,14 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_default_branch" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_default_branch_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_default_branch" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetDefaultBranchRequest.pb( catalog_service.GetDefaultBranchRequest() ) @@ -8408,6 +8475,10 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.GetDefaultBranchResponse() + post_with_metadata.return_value = ( + catalog_service.GetDefaultBranchResponse(), + metadata, + ) client.get_default_branch( request, @@ -8419,6 +8490,7 @@ def test_get_default_branch_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_completion_config_rest_bad_request( @@ -8530,10 +8602,14 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetCompletionConfigRequest.pb( catalog_service.GetCompletionConfigRequest() ) @@ -8557,6 +8633,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.get_completion_config( request, @@ -8568,6 +8645,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_completion_config_rest_bad_request( @@ -8774,10 +8852,14 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCompletionConfigRequest.pb( catalog_service.UpdateCompletionConfigRequest() ) @@ -8801,6 +8883,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.update_completion_config( request, @@ -8812,6 +8895,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_attributes_config_rest_bad_request( @@ -8905,10 +8989,14 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetAttributesConfigRequest.pb( catalog_service.GetAttributesConfigRequest() ) @@ -8932,6 +9020,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.get_attributes_config( request, @@ -8943,6 +9032,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_attributes_config_rest_bad_request( @@ -9114,10 +9204,14 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateAttributesConfigRequest.pb( catalog_service.UpdateAttributesConfigRequest() ) @@ -9141,6 +9235,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.update_attributes_config( request, @@ -9152,6 +9247,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_catalog_attribute_rest_bad_request( @@ -9245,10 +9341,14 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_add_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_add_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_add_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.AddCatalogAttributeRequest.pb( catalog_service.AddCatalogAttributeRequest() ) @@ -9272,6 +9372,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.add_catalog_attribute( request, @@ -9283,6 +9384,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_catalog_attribute_rest_bad_request( @@ -9376,10 +9478,14 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_remove_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_remove_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_remove_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.RemoveCatalogAttributeRequest.pb( catalog_service.RemoveCatalogAttributeRequest() ) @@ -9403,6 +9509,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.remove_catalog_attribute( request, @@ -9414,6 +9521,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_remove_catalog_attributes_rest_bad_request( @@ -9506,10 +9614,14 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_batch_remove_catalog_attributes" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_batch_remove_catalog_attributes_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_batch_remove_catalog_attributes" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.BatchRemoveCatalogAttributesRequest.pb( catalog_service.BatchRemoveCatalogAttributesRequest() ) @@ -9535,6 +9647,10 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.BatchRemoveCatalogAttributesResponse() + post_with_metadata.return_value = ( + catalog_service.BatchRemoveCatalogAttributesResponse(), + metadata, + ) client.batch_remove_catalog_attributes( request, @@ -9546,6 +9662,7 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_replace_catalog_attribute_rest_bad_request( @@ -9639,10 +9756,14 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_replace_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_replace_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_replace_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ReplaceCatalogAttributeRequest.pb( catalog_service.ReplaceCatalogAttributeRequest() ) @@ -9666,6 +9787,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.replace_catalog_attribute( request, @@ -9677,6 +9799,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_completion_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_completion_service.py index 3a7ac5195d92..8cb4296e8606 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_completion_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_completion_service.py @@ -71,6 +71,13 @@ ) from google.cloud.retail_v2alpha.types import completion_service, import_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2231,10 +2281,13 @@ def test_complete_query_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CompletionServiceRestInterceptor, "post_complete_query" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, "post_complete_query_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_complete_query" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = completion_service.CompleteQueryRequest.pb( completion_service.CompleteQueryRequest() ) @@ -2260,6 +2313,10 @@ def test_complete_query_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = completion_service.CompleteQueryResponse() + post_with_metadata.return_value = ( + completion_service.CompleteQueryResponse(), + metadata, + ) client.complete_query( request, @@ -2271,6 +2328,7 @@ def test_complete_query_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_completion_data_rest_bad_request( @@ -2351,10 +2409,14 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CompletionServiceRestInterceptor, "post_import_completion_data" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, + "post_import_completion_data_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_import_completion_data" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportCompletionDataRequest.pb( import_config.ImportCompletionDataRequest() ) @@ -2378,6 +2440,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_completion_data( request, @@ -2389,6 +2452,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_control_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_control_service.py index 4e38d91a9315..4c8233dd6f97 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_control_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_control_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2alpha.types import control as gcr_control from google.cloud.retail_v2alpha.types import control_service, search_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4702,10 +4752,13 @@ def test_create_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_create_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_create_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_create_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.CreateControlRequest.pb( control_service.CreateControlRequest() ) @@ -4729,6 +4782,7 @@ def test_create_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.create_control( request, @@ -4740,6 +4794,7 @@ def test_create_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_control_rest_bad_request( @@ -5112,10 +5167,13 @@ def test_update_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_update_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_update_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_update_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.UpdateControlRequest.pb( control_service.UpdateControlRequest() ) @@ -5139,6 +5197,7 @@ def test_update_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.update_control( request, @@ -5150,6 +5209,7 @@ def test_update_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_control_rest_bad_request(request_type=control_service.GetControlRequest): @@ -5250,10 +5310,13 @@ def test_get_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_get_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_get_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_get_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.GetControlRequest.pb( control_service.GetControlRequest() ) @@ -5277,6 +5340,7 @@ def test_get_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control.Control() + post_with_metadata.return_value = control.Control(), metadata client.get_control( request, @@ -5288,6 +5352,7 @@ def test_get_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_controls_rest_bad_request( @@ -5372,10 +5437,13 @@ def test_list_controls_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_list_controls" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_list_controls_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_list_controls" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.ListControlsRequest.pb( control_service.ListControlsRequest() ) @@ -5401,6 +5469,10 @@ def test_list_controls_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control_service.ListControlsResponse() + post_with_metadata.return_value = ( + control_service.ListControlsResponse(), + metadata, + ) client.list_controls( request, @@ -5412,6 +5484,7 @@ def test_list_controls_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_generative_question_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_generative_question_service.py index ccfb419462f6..7521e4b6d4d6 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_generative_question_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_generative_question_service.py @@ -65,6 +65,13 @@ generative_question_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -344,6 +351,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4625,11 +4675,15 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest() ) @@ -4657,6 +4711,10 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.update_generative_questions_feature_config( request, @@ -4668,6 +4726,7 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_generative_questions_feature_config_rest_bad_request( @@ -4759,11 +4818,15 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep transports.GenerativeQuestionServiceRestInterceptor, "post_get_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_get_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_get_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest() @@ -4793,6 +4856,10 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.get_generative_questions_feature_config( request, @@ -4804,6 +4871,7 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_generative_question_configs_rest_bad_request( @@ -4894,11 +4962,15 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_list_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_list_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_list_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.ListGenerativeQuestionConfigsRequest.pb( generative_question_service.ListGenerativeQuestionConfigsRequest() @@ -4930,6 +5002,10 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): post.return_value = ( generative_question_service.ListGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.ListGenerativeQuestionConfigsResponse(), + metadata, + ) client.list_generative_question_configs( request, @@ -4941,6 +5017,7 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_generative_question_config_rest_bad_request( @@ -5130,11 +5207,15 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_question_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_question_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_question_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.UpdateGenerativeQuestionConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionConfigRequest() @@ -5162,6 +5243,10 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionConfig(), + metadata, + ) client.update_generative_question_config( request, @@ -5173,6 +5258,7 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_update_generative_question_configs_rest_bad_request( @@ -5264,11 +5350,15 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce transports.GenerativeQuestionServiceRestInterceptor, "post_batch_update_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_batch_update_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_batch_update_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest.pb( generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest() ) @@ -5298,6 +5388,10 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce post.return_value = ( generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse(), + metadata, + ) client.batch_update_generative_question_configs( request, @@ -5309,6 +5403,7 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_merchant_center_account_link_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_merchant_center_account_link_service.py index 51543b6cd09d..2d69cc451776 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_merchant_center_account_link_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_merchant_center_account_link_service.py @@ -74,6 +74,13 @@ from google.cloud.retail_v2alpha.types import merchant_center_account_link_service from google.cloud.retail_v2alpha.types import merchant_center_account_link +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -368,6 +375,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = MerchantCenterAccountLinkServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = MerchantCenterAccountLinkServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -3223,11 +3273,15 @@ def test_list_merchant_center_account_links_rest_interceptors(null_interceptor): transports.MerchantCenterAccountLinkServiceRestInterceptor, "post_list_merchant_center_account_links", ) as post, mock.patch.object( + transports.MerchantCenterAccountLinkServiceRestInterceptor, + "post_list_merchant_center_account_links_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MerchantCenterAccountLinkServiceRestInterceptor, "pre_list_merchant_center_account_links", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = merchant_center_account_link_service.ListMerchantCenterAccountLinksRequest.pb( merchant_center_account_link_service.ListMerchantCenterAccountLinksRequest() ) @@ -3257,6 +3311,10 @@ def test_list_merchant_center_account_links_rest_interceptors(null_interceptor): post.return_value = ( merchant_center_account_link_service.ListMerchantCenterAccountLinksResponse() ) + post_with_metadata.return_value = ( + merchant_center_account_link_service.ListMerchantCenterAccountLinksResponse(), + metadata, + ) client.list_merchant_center_account_links( request, @@ -3268,6 +3326,7 @@ def test_list_merchant_center_account_links_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_merchant_center_account_link_rest_bad_request( @@ -3436,11 +3495,15 @@ def test_create_merchant_center_account_link_rest_interceptors(null_interceptor) transports.MerchantCenterAccountLinkServiceRestInterceptor, "post_create_merchant_center_account_link", ) as post, mock.patch.object( + transports.MerchantCenterAccountLinkServiceRestInterceptor, + "post_create_merchant_center_account_link_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.MerchantCenterAccountLinkServiceRestInterceptor, "pre_create_merchant_center_account_link", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = merchant_center_account_link_service.CreateMerchantCenterAccountLinkRequest.pb( merchant_center_account_link_service.CreateMerchantCenterAccountLinkRequest() ) @@ -3466,6 +3529,7 @@ def test_create_merchant_center_account_link_rest_interceptors(null_interceptor) ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_merchant_center_account_link( request, @@ -3477,6 +3541,7 @@ def test_create_merchant_center_account_link_rest_interceptors(null_interceptor) pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_merchant_center_account_link_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_model_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_model_service.py index 71bf19a1a07d..b4a9beade991 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_model_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_model_service.py @@ -76,6 +76,13 @@ from google.cloud.retail_v2alpha.types import model as gcr_model from google.cloud.retail_v2alpha.types import model_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6324,10 +6374,13 @@ def test_create_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_create_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_create_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_create_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.CreateModelRequest.pb( model_service.CreateModelRequest() ) @@ -6351,6 +6404,7 @@ def test_create_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_model( request, @@ -6362,6 +6416,7 @@ def test_create_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_model_rest_bad_request(request_type=model_service.GetModelRequest): @@ -6472,10 +6527,13 @@ def test_get_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_get_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_get_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_get_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.GetModelRequest.pb(model_service.GetModelRequest()) transcode.return_value = { "method": "post", @@ -6497,6 +6555,7 @@ def test_get_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.get_model( request, @@ -6508,6 +6567,7 @@ def test_get_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_pause_model_rest_bad_request(request_type=model_service.PauseModelRequest): @@ -6618,10 +6678,13 @@ def test_pause_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_pause_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_pause_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_pause_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.PauseModelRequest.pb( model_service.PauseModelRequest() ) @@ -6645,6 +6708,7 @@ def test_pause_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.pause_model( request, @@ -6656,6 +6720,7 @@ def test_pause_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_model_rest_bad_request(request_type=model_service.ResumeModelRequest): @@ -6766,10 +6831,13 @@ def test_resume_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_resume_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_resume_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_resume_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ResumeModelRequest.pb( model_service.ResumeModelRequest() ) @@ -6793,6 +6861,7 @@ def test_resume_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.resume_model( request, @@ -6804,6 +6873,7 @@ def test_resume_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_model_rest_bad_request(request_type=model_service.DeleteModelRequest): @@ -6997,10 +7067,13 @@ def test_list_models_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_list_models" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_list_models_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_list_models" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ListModelsRequest.pb( model_service.ListModelsRequest() ) @@ -7026,6 +7099,7 @@ def test_list_models_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model_service.ListModelsResponse() + post_with_metadata.return_value = model_service.ListModelsResponse(), metadata client.list_models( request, @@ -7037,6 +7111,7 @@ def test_list_models_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_model_rest_bad_request(request_type=model_service.UpdateModelRequest): @@ -7258,10 +7333,13 @@ def test_update_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_update_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_update_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_update_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.UpdateModelRequest.pb( model_service.UpdateModelRequest() ) @@ -7285,6 +7363,7 @@ def test_update_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_model.Model() + post_with_metadata.return_value = gcr_model.Model(), metadata client.update_model( request, @@ -7296,6 +7375,7 @@ def test_update_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_tune_model_rest_bad_request(request_type=model_service.TuneModelRequest): @@ -7378,10 +7458,13 @@ def test_tune_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_tune_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_tune_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_tune_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.TuneModelRequest.pb(model_service.TuneModelRequest()) transcode.return_value = { "method": "post", @@ -7403,6 +7486,7 @@ def test_tune_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.tune_model( request, @@ -7414,6 +7498,7 @@ def test_tune_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_prediction_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_prediction_service.py index 29a412631659..3cc420f6b3ac 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_prediction_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_prediction_service.py @@ -72,6 +72,13 @@ user_event, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,13 @@ def test_predict_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PredictionServiceRestInterceptor, "post_predict" ) as post, mock.patch.object( + transports.PredictionServiceRestInterceptor, "post_predict_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PredictionServiceRestInterceptor, "pre_predict" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_service.PredictRequest.pb( prediction_service.PredictRequest() ) @@ -1782,6 +1835,7 @@ def test_predict_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = prediction_service.PredictResponse() + post_with_metadata.return_value = prediction_service.PredictResponse(), metadata client.predict( request, @@ -1793,6 +1847,7 @@ def test_predict_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_product_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_product_service.py index 61d1a8ff3a0b..31c5b5f5a70e 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_product_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_product_service.py @@ -79,6 +79,13 @@ from google.cloud.retail_v2alpha.types import product from google.cloud.retail_v2alpha.types import product as gcr_product +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -9056,10 +9106,13 @@ def test_create_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_create_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_create_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_create_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.CreateProductRequest.pb( product_service.CreateProductRequest() ) @@ -9083,6 +9136,7 @@ def test_create_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.create_product( request, @@ -9094,6 +9148,7 @@ def test_create_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_product_rest_bad_request(request_type=product_service.GetProductRequest): @@ -9214,10 +9269,13 @@ def test_get_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_get_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_get_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_get_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.GetProductRequest.pb( product_service.GetProductRequest() ) @@ -9241,6 +9299,7 @@ def test_get_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product.Product() + post_with_metadata.return_value = product.Product(), metadata client.get_product( request, @@ -9252,6 +9311,7 @@ def test_get_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_products_rest_bad_request( @@ -9342,10 +9402,13 @@ def test_list_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_list_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_list_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_list_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.ListProductsRequest.pb( product_service.ListProductsRequest() ) @@ -9371,6 +9434,10 @@ def test_list_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product_service.ListProductsResponse() + post_with_metadata.return_value = ( + product_service.ListProductsResponse(), + metadata, + ) client.list_products( request, @@ -9382,6 +9449,7 @@ def test_list_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_product_rest_bad_request( @@ -9655,10 +9723,13 @@ def test_update_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_update_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_update_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_update_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.UpdateProductRequest.pb( product_service.UpdateProductRequest() ) @@ -9682,6 +9753,7 @@ def test_update_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.update_product( request, @@ -9693,6 +9765,7 @@ def test_update_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_product_rest_bad_request( @@ -9890,10 +9963,13 @@ def test_purge_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_purge_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_purge_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_purge_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeProductsRequest.pb( purge_config.PurgeProductsRequest() ) @@ -9917,6 +9993,7 @@ def test_purge_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_products( request, @@ -9928,6 +10005,7 @@ def test_purge_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_products_rest_bad_request( @@ -10012,10 +10090,13 @@ def test_import_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_import_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_import_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_import_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportProductsRequest.pb( import_config.ImportProductsRequest() ) @@ -10039,6 +10120,7 @@ def test_import_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_products( request, @@ -10050,6 +10132,7 @@ def test_import_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_products_rest_bad_request( @@ -10134,10 +10217,13 @@ def test_export_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_export_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_export_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_export_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportProductsRequest.pb( export_config.ExportProductsRequest() ) @@ -10161,6 +10247,7 @@ def test_export_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_products( request, @@ -10172,6 +10259,7 @@ def test_export_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_inventory_rest_bad_request( @@ -10260,10 +10348,13 @@ def test_set_inventory_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_set_inventory" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_set_inventory_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_set_inventory" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.SetInventoryRequest.pb( product_service.SetInventoryRequest() ) @@ -10287,6 +10378,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.set_inventory( request, @@ -10298,6 +10390,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_fulfillment_places_rest_bad_request( @@ -10382,10 +10475,14 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddFulfillmentPlacesRequest.pb( product_service.AddFulfillmentPlacesRequest() ) @@ -10409,6 +10506,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_fulfillment_places( request, @@ -10420,6 +10518,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_fulfillment_places_rest_bad_request( @@ -10504,10 +10603,14 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveFulfillmentPlacesRequest.pb( product_service.RemoveFulfillmentPlacesRequest() ) @@ -10531,6 +10634,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_fulfillment_places( request, @@ -10542,6 +10646,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_local_inventories_rest_bad_request( @@ -10626,10 +10731,14 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddLocalInventoriesRequest.pb( product_service.AddLocalInventoriesRequest() ) @@ -10653,6 +10762,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_local_inventories( request, @@ -10664,6 +10774,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_local_inventories_rest_bad_request( @@ -10748,10 +10859,14 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveLocalInventoriesRequest.pb( product_service.RemoveLocalInventoriesRequest() ) @@ -10775,6 +10890,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_local_inventories( request, @@ -10786,6 +10902,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_project_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_project_service.py index d0d185518a0d..e5f3bdbb1c69 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_project_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_project_service.py @@ -74,6 +74,13 @@ from google.cloud.retail_v2alpha.types import project as gcr_project from google.cloud.retail_v2alpha.types import project_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -332,6 +339,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProjectServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProjectServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -5681,10 +5731,13 @@ def test_get_project_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_get_project" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, "post_get_project_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_get_project" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.GetProjectRequest.pb( project_service.GetProjectRequest() ) @@ -5708,6 +5761,7 @@ def test_get_project_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.Project() + post_with_metadata.return_value = project.Project(), metadata client.get_project( request, @@ -5719,6 +5773,7 @@ def test_get_project_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_accept_terms_rest_bad_request(request_type=project_service.AcceptTermsRequest): @@ -5805,10 +5860,13 @@ def test_accept_terms_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_accept_terms" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, "post_accept_terms_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_accept_terms" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.AcceptTermsRequest.pb( project_service.AcceptTermsRequest() ) @@ -5832,6 +5890,7 @@ def test_accept_terms_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_project.Project() + post_with_metadata.return_value = gcr_project.Project(), metadata client.accept_terms( request, @@ -5843,6 +5902,7 @@ def test_accept_terms_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_enroll_solution_rest_bad_request( @@ -5923,10 +5983,13 @@ def test_enroll_solution_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProjectServiceRestInterceptor, "post_enroll_solution" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, "post_enroll_solution_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_enroll_solution" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.EnrollSolutionRequest.pb( project_service.EnrollSolutionRequest() ) @@ -5950,6 +6013,7 @@ def test_enroll_solution_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.enroll_solution( request, @@ -5961,6 +6025,7 @@ def test_enroll_solution_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_enrolled_solutions_rest_bad_request( @@ -6047,10 +6112,14 @@ def test_list_enrolled_solutions_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_list_enrolled_solutions" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, + "post_list_enrolled_solutions_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_list_enrolled_solutions" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.ListEnrolledSolutionsRequest.pb( project_service.ListEnrolledSolutionsRequest() ) @@ -6076,6 +6145,10 @@ def test_list_enrolled_solutions_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project_service.ListEnrolledSolutionsResponse() + post_with_metadata.return_value = ( + project_service.ListEnrolledSolutionsResponse(), + metadata, + ) client.list_enrolled_solutions( request, @@ -6087,6 +6160,7 @@ def test_list_enrolled_solutions_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_logging_config_rest_bad_request( @@ -6171,10 +6245,14 @@ def test_get_logging_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_get_logging_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, + "post_get_logging_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_get_logging_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.GetLoggingConfigRequest.pb( project_service.GetLoggingConfigRequest() ) @@ -6198,6 +6276,7 @@ def test_get_logging_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.LoggingConfig() + post_with_metadata.return_value = project.LoggingConfig(), metadata client.get_logging_config( request, @@ -6209,6 +6288,7 @@ def test_get_logging_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_logging_config_rest_bad_request( @@ -6372,10 +6452,14 @@ def test_update_logging_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_update_logging_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, + "post_update_logging_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_update_logging_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.UpdateLoggingConfigRequest.pb( project_service.UpdateLoggingConfigRequest() ) @@ -6399,6 +6483,7 @@ def test_update_logging_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.LoggingConfig() + post_with_metadata.return_value = project.LoggingConfig(), metadata client.update_logging_config( request, @@ -6410,6 +6495,7 @@ def test_update_logging_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_alert_config_rest_bad_request( @@ -6494,10 +6580,13 @@ def test_get_alert_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_get_alert_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, "post_get_alert_config_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_get_alert_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.GetAlertConfigRequest.pb( project_service.GetAlertConfigRequest() ) @@ -6521,6 +6610,7 @@ def test_get_alert_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.AlertConfig() + post_with_metadata.return_value = project.AlertConfig(), metadata client.get_alert_config( request, @@ -6532,6 +6622,7 @@ def test_get_alert_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_alert_config_rest_bad_request( @@ -6693,10 +6784,14 @@ def test_update_alert_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_update_alert_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, + "post_update_alert_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_update_alert_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.UpdateAlertConfigRequest.pb( project_service.UpdateAlertConfigRequest() ) @@ -6720,6 +6815,7 @@ def test_update_alert_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.AlertConfig() + post_with_metadata.return_value = project.AlertConfig(), metadata client.update_alert_config( request, @@ -6731,6 +6827,7 @@ def test_update_alert_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_search_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_search_service.py index 391881054acf..ada6701ad1ae 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_search_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_search_service.py @@ -62,6 +62,13 @@ ) from google.cloud.retail_v2alpha.types import common, search_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -316,6 +323,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1999,10 +2049,13 @@ def test_search_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SearchServiceRestInterceptor, "post_search" ) as post, mock.patch.object( + transports.SearchServiceRestInterceptor, "post_search_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SearchServiceRestInterceptor, "pre_search" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = search_service.SearchRequest.pb(search_service.SearchRequest()) transcode.return_value = { "method": "post", @@ -2026,6 +2079,7 @@ def test_search_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = search_service.SearchResponse() + post_with_metadata.return_value = search_service.SearchResponse(), metadata client.search( request, @@ -2037,6 +2091,7 @@ def test_search_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_serving_config_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_serving_config_service.py index cd9b8d978c02..fd3b999cee55 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_serving_config_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_serving_config_service.py @@ -66,6 +66,13 @@ from google.cloud.retail_v2alpha.types import serving_config from google.cloud.retail_v2alpha.types import serving_config_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6318,10 +6368,14 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_create_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_create_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_create_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.CreateServingConfigRequest.pb( serving_config_service.CreateServingConfigRequest() ) @@ -6347,6 +6401,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.create_serving_config( request, @@ -6358,6 +6413,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_serving_config_rest_bad_request( @@ -6714,10 +6770,14 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_update_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_update_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_update_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.UpdateServingConfigRequest.pb( serving_config_service.UpdateServingConfigRequest() ) @@ -6743,6 +6803,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.update_serving_config( request, @@ -6754,6 +6815,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_serving_config_rest_bad_request( @@ -6881,10 +6943,14 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_get_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_get_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_get_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.GetServingConfigRequest.pb( serving_config_service.GetServingConfigRequest() ) @@ -6910,6 +6976,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config.ServingConfig() + post_with_metadata.return_value = serving_config.ServingConfig(), metadata client.get_serving_config( request, @@ -6921,6 +6988,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_serving_configs_rest_bad_request( @@ -7007,10 +7075,14 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_list_serving_configs" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_list_serving_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_list_serving_configs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.ListServingConfigsRequest.pb( serving_config_service.ListServingConfigsRequest() ) @@ -7036,6 +7108,10 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config_service.ListServingConfigsResponse() + post_with_metadata.return_value = ( + serving_config_service.ListServingConfigsResponse(), + metadata, + ) client.list_serving_configs( request, @@ -7047,6 +7123,7 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_control_rest_bad_request( @@ -7174,10 +7251,13 @@ def test_add_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_add_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, "post_add_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_add_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.AddControlRequest.pb( serving_config_service.AddControlRequest() ) @@ -7203,6 +7283,7 @@ def test_add_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.add_control( request, @@ -7214,6 +7295,7 @@ def test_add_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_control_rest_bad_request( @@ -7341,10 +7423,14 @@ def test_remove_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_remove_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_remove_control_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_remove_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.RemoveControlRequest.pb( serving_config_service.RemoveControlRequest() ) @@ -7370,6 +7456,7 @@ def test_remove_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.remove_control( request, @@ -7381,6 +7468,7 @@ def test_remove_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_user_event_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_user_event_service.py index 2e7ec0b0fa0a..a89fbed19cfc 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_user_event_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2alpha/test_user_event_service.py @@ -86,6 +86,13 @@ user_event_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -345,6 +352,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4291,10 +4341,14 @@ def test_write_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_write_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_write_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_write_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.WriteUserEventRequest.pb( user_event_service.WriteUserEventRequest() ) @@ -4318,6 +4372,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user_event.UserEvent() + post_with_metadata.return_value = user_event.UserEvent(), metadata client.write_user_event( request, @@ -4329,6 +4384,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_collect_user_event_rest_bad_request( @@ -4412,10 +4468,14 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_collect_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_collect_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_collect_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.CollectUserEventRequest.pb( user_event_service.CollectUserEventRequest() ) @@ -4439,6 +4499,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = httpbody_pb2.HttpBody() + post_with_metadata.return_value = httpbody_pb2.HttpBody(), metadata client.collect_user_event( request, @@ -4450,6 +4511,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_purge_user_events_rest_bad_request( @@ -4530,10 +4592,14 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_purge_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_purge_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_purge_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeUserEventsRequest.pb( purge_config.PurgeUserEventsRequest() ) @@ -4557,6 +4623,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_user_events( request, @@ -4568,6 +4635,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_user_events_rest_bad_request( @@ -4648,10 +4716,14 @@ def test_import_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_import_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_import_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_import_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportUserEventsRequest.pb( import_config.ImportUserEventsRequest() ) @@ -4675,6 +4747,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_user_events( request, @@ -4686,6 +4759,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_user_events_rest_bad_request( @@ -4766,10 +4840,14 @@ def test_export_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_export_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_export_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_export_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportUserEventsRequest.pb( export_config.ExportUserEventsRequest() ) @@ -4793,6 +4871,7 @@ def test_export_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_user_events( request, @@ -4804,6 +4883,7 @@ def test_export_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_rejoin_user_events_rest_bad_request( @@ -4884,10 +4964,14 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_rejoin_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_rejoin_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_rejoin_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.RejoinUserEventsRequest.pb( user_event_service.RejoinUserEventsRequest() ) @@ -4911,6 +4995,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.rejoin_user_events( request, @@ -4922,6 +5007,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_analytics_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_analytics_service.py index 39041b69dcd9..c28b9ad7e1b8 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_analytics_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_analytics_service.py @@ -70,6 +70,13 @@ ) from google.cloud.retail_v2beta.types import export_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -329,6 +336,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = AnalyticsServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,14 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ), mock.patch.object( transports.AnalyticsServiceRestInterceptor, "post_export_analytics_metrics" ) as post, mock.patch.object( + transports.AnalyticsServiceRestInterceptor, + "post_export_analytics_metrics_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.AnalyticsServiceRestInterceptor, "pre_export_analytics_metrics" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportAnalyticsMetricsRequest.pb( export_config.ExportAnalyticsMetricsRequest() ) @@ -1780,6 +1834,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_analytics_metrics( request, @@ -1791,6 +1846,7 @@ def test_export_analytics_metrics_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_catalog_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_catalog_service.py index c4ae0b1dec4d..6bfaa59cbcf7 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_catalog_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_catalog_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2beta.types import catalog from google.cloud.retail_v2beta.types import catalog as gcr_catalog +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CatalogServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -7924,10 +7974,13 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_list_catalogs" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_list_catalogs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_list_catalogs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ListCatalogsRequest.pb( catalog_service.ListCatalogsRequest() ) @@ -7953,6 +8006,10 @@ def test_list_catalogs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.ListCatalogsResponse() + post_with_metadata.return_value = ( + catalog_service.ListCatalogsResponse(), + metadata, + ) client.list_catalogs( request, @@ -7964,6 +8021,7 @@ def test_list_catalogs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_catalog_rest_bad_request( @@ -8146,10 +8204,13 @@ def test_update_catalog_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_catalog" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, "post_update_catalog_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_catalog" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCatalogRequest.pb( catalog_service.UpdateCatalogRequest() ) @@ -8173,6 +8234,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_catalog.Catalog() + post_with_metadata.return_value = gcr_catalog.Catalog(), metadata client.update_catalog( request, @@ -8184,6 +8246,7 @@ def test_update_catalog_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_default_branch_rest_bad_request( @@ -8379,10 +8442,14 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_default_branch" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_default_branch_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_default_branch" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetDefaultBranchRequest.pb( catalog_service.GetDefaultBranchRequest() ) @@ -8408,6 +8475,10 @@ def test_get_default_branch_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.GetDefaultBranchResponse() + post_with_metadata.return_value = ( + catalog_service.GetDefaultBranchResponse(), + metadata, + ) client.get_default_branch( request, @@ -8419,6 +8490,7 @@ def test_get_default_branch_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_completion_config_rest_bad_request( @@ -8530,10 +8602,14 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetCompletionConfigRequest.pb( catalog_service.GetCompletionConfigRequest() ) @@ -8557,6 +8633,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.get_completion_config( request, @@ -8568,6 +8645,7 @@ def test_get_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_completion_config_rest_bad_request( @@ -8774,10 +8852,14 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_completion_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_completion_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_completion_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateCompletionConfigRequest.pb( catalog_service.UpdateCompletionConfigRequest() ) @@ -8801,6 +8883,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.CompletionConfig() + post_with_metadata.return_value = catalog.CompletionConfig(), metadata client.update_completion_config( request, @@ -8812,6 +8895,7 @@ def test_update_completion_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_attributes_config_rest_bad_request( @@ -8905,10 +8989,14 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_get_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_get_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_get_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.GetAttributesConfigRequest.pb( catalog_service.GetAttributesConfigRequest() ) @@ -8932,6 +9020,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.get_attributes_config( request, @@ -8943,6 +9032,7 @@ def test_get_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_attributes_config_rest_bad_request( @@ -9114,10 +9204,14 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_update_attributes_config" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_update_attributes_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_update_attributes_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.UpdateAttributesConfigRequest.pb( catalog_service.UpdateAttributesConfigRequest() ) @@ -9141,6 +9235,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.update_attributes_config( request, @@ -9152,6 +9247,7 @@ def test_update_attributes_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_catalog_attribute_rest_bad_request( @@ -9245,10 +9341,14 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_add_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_add_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_add_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.AddCatalogAttributeRequest.pb( catalog_service.AddCatalogAttributeRequest() ) @@ -9272,6 +9372,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.add_catalog_attribute( request, @@ -9283,6 +9384,7 @@ def test_add_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_catalog_attribute_rest_bad_request( @@ -9376,10 +9478,14 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_remove_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_remove_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_remove_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.RemoveCatalogAttributeRequest.pb( catalog_service.RemoveCatalogAttributeRequest() ) @@ -9403,6 +9509,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.remove_catalog_attribute( request, @@ -9414,6 +9521,7 @@ def test_remove_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_remove_catalog_attributes_rest_bad_request( @@ -9506,10 +9614,14 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_batch_remove_catalog_attributes" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_batch_remove_catalog_attributes_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_batch_remove_catalog_attributes" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.BatchRemoveCatalogAttributesRequest.pb( catalog_service.BatchRemoveCatalogAttributesRequest() ) @@ -9535,6 +9647,10 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog_service.BatchRemoveCatalogAttributesResponse() + post_with_metadata.return_value = ( + catalog_service.BatchRemoveCatalogAttributesResponse(), + metadata, + ) client.batch_remove_catalog_attributes( request, @@ -9546,6 +9662,7 @@ def test_batch_remove_catalog_attributes_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_replace_catalog_attribute_rest_bad_request( @@ -9639,10 +9756,14 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CatalogServiceRestInterceptor, "post_replace_catalog_attribute" ) as post, mock.patch.object( + transports.CatalogServiceRestInterceptor, + "post_replace_catalog_attribute_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CatalogServiceRestInterceptor, "pre_replace_catalog_attribute" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = catalog_service.ReplaceCatalogAttributeRequest.pb( catalog_service.ReplaceCatalogAttributeRequest() ) @@ -9666,6 +9787,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = catalog.AttributesConfig() + post_with_metadata.return_value = catalog.AttributesConfig(), metadata client.replace_catalog_attribute( request, @@ -9677,6 +9799,7 @@ def test_replace_catalog_attribute_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_completion_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_completion_service.py index 36306639e32a..2a38f6366d31 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_completion_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_completion_service.py @@ -71,6 +71,13 @@ ) from google.cloud.retail_v2beta.types import completion_service, import_config +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -338,6 +345,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CompletionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2231,10 +2281,13 @@ def test_complete_query_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CompletionServiceRestInterceptor, "post_complete_query" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, "post_complete_query_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_complete_query" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = completion_service.CompleteQueryRequest.pb( completion_service.CompleteQueryRequest() ) @@ -2260,6 +2313,10 @@ def test_complete_query_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = completion_service.CompleteQueryResponse() + post_with_metadata.return_value = ( + completion_service.CompleteQueryResponse(), + metadata, + ) client.complete_query( request, @@ -2271,6 +2328,7 @@ def test_complete_query_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_completion_data_rest_bad_request( @@ -2351,10 +2409,14 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ), mock.patch.object( transports.CompletionServiceRestInterceptor, "post_import_completion_data" ) as post, mock.patch.object( + transports.CompletionServiceRestInterceptor, + "post_import_completion_data_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.CompletionServiceRestInterceptor, "pre_import_completion_data" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportCompletionDataRequest.pb( import_config.ImportCompletionDataRequest() ) @@ -2378,6 +2440,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_completion_data( request, @@ -2389,6 +2452,7 @@ def test_import_completion_data_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_control_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_control_service.py index f38696bd2f89..50ab423e654d 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_control_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_control_service.py @@ -67,6 +67,13 @@ from google.cloud.retail_v2beta.types import control as gcr_control from google.cloud.retail_v2beta.types import control_service, search_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -325,6 +332,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ControlServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4702,10 +4752,13 @@ def test_create_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_create_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_create_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_create_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.CreateControlRequest.pb( control_service.CreateControlRequest() ) @@ -4729,6 +4782,7 @@ def test_create_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.create_control( request, @@ -4740,6 +4794,7 @@ def test_create_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_control_rest_bad_request( @@ -5112,10 +5167,13 @@ def test_update_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_update_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_update_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_update_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.UpdateControlRequest.pb( control_service.UpdateControlRequest() ) @@ -5139,6 +5197,7 @@ def test_update_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_control.Control() + post_with_metadata.return_value = gcr_control.Control(), metadata client.update_control( request, @@ -5150,6 +5209,7 @@ def test_update_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_control_rest_bad_request(request_type=control_service.GetControlRequest): @@ -5250,10 +5310,13 @@ def test_get_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_get_control" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_get_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_get_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.GetControlRequest.pb( control_service.GetControlRequest() ) @@ -5277,6 +5340,7 @@ def test_get_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control.Control() + post_with_metadata.return_value = control.Control(), metadata client.get_control( request, @@ -5288,6 +5352,7 @@ def test_get_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_controls_rest_bad_request( @@ -5372,10 +5437,13 @@ def test_list_controls_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ControlServiceRestInterceptor, "post_list_controls" ) as post, mock.patch.object( + transports.ControlServiceRestInterceptor, "post_list_controls_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ControlServiceRestInterceptor, "pre_list_controls" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = control_service.ListControlsRequest.pb( control_service.ListControlsRequest() ) @@ -5401,6 +5469,10 @@ def test_list_controls_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = control_service.ListControlsResponse() + post_with_metadata.return_value = ( + control_service.ListControlsResponse(), + metadata, + ) client.list_controls( request, @@ -5412,6 +5484,7 @@ def test_list_controls_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_generative_question_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_generative_question_service.py index e691152ffbf3..ae96cac88a41 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_generative_question_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_generative_question_service.py @@ -65,6 +65,13 @@ generative_question_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -344,6 +351,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = GenerativeQuestionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4625,11 +4675,15 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionsFeatureConfigRequest() ) @@ -4657,6 +4711,10 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.update_generative_questions_feature_config( request, @@ -4668,6 +4726,7 @@ def test_update_generative_questions_feature_config_rest_interceptors(null_inter pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_generative_questions_feature_config_rest_bad_request( @@ -4759,11 +4818,15 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep transports.GenerativeQuestionServiceRestInterceptor, "post_get_generative_questions_feature_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_get_generative_questions_feature_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_get_generative_questions_feature_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest.pb( generative_question_service.GetGenerativeQuestionsFeatureConfigRequest() @@ -4793,6 +4856,10 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionsFeatureConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionsFeatureConfig(), + metadata, + ) client.get_generative_questions_feature_config( request, @@ -4804,6 +4871,7 @@ def test_get_generative_questions_feature_config_rest_interceptors(null_intercep pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_generative_question_configs_rest_bad_request( @@ -4894,11 +4962,15 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_list_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_list_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_list_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.ListGenerativeQuestionConfigsRequest.pb( generative_question_service.ListGenerativeQuestionConfigsRequest() @@ -4930,6 +5002,10 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): post.return_value = ( generative_question_service.ListGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.ListGenerativeQuestionConfigsResponse(), + metadata, + ) client.list_generative_question_configs( request, @@ -4941,6 +5017,7 @@ def test_list_generative_question_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_generative_question_config_rest_bad_request( @@ -5130,11 +5207,15 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): transports.GenerativeQuestionServiceRestInterceptor, "post_update_generative_question_config", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_update_generative_question_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_update_generative_question_config", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = ( generative_question_service.UpdateGenerativeQuestionConfigRequest.pb( generative_question_service.UpdateGenerativeQuestionConfigRequest() @@ -5162,6 +5243,10 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = generative_question.GenerativeQuestionConfig() + post_with_metadata.return_value = ( + generative_question.GenerativeQuestionConfig(), + metadata, + ) client.update_generative_question_config( request, @@ -5173,6 +5258,7 @@ def test_update_generative_question_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_batch_update_generative_question_configs_rest_bad_request( @@ -5264,11 +5350,15 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce transports.GenerativeQuestionServiceRestInterceptor, "post_batch_update_generative_question_configs", ) as post, mock.patch.object( + transports.GenerativeQuestionServiceRestInterceptor, + "post_batch_update_generative_question_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.GenerativeQuestionServiceRestInterceptor, "pre_batch_update_generative_question_configs", ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest.pb( generative_question_service.BatchUpdateGenerativeQuestionConfigsRequest() ) @@ -5298,6 +5388,10 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce post.return_value = ( generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse() ) + post_with_metadata.return_value = ( + generative_question_service.BatchUpdateGenerativeQuestionConfigsResponse(), + metadata, + ) client.batch_update_generative_question_configs( request, @@ -5309,6 +5403,7 @@ def test_batch_update_generative_question_configs_rest_interceptors(null_interce pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_model_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_model_service.py index 9fa9f853036a..0d788107a59e 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_model_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_model_service.py @@ -76,6 +76,13 @@ from google.cloud.retail_v2beta.types import model as gcr_model from google.cloud.retail_v2beta.types import model_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -319,6 +326,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ModelServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6246,10 +6296,13 @@ def test_create_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_create_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_create_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_create_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.CreateModelRequest.pb( model_service.CreateModelRequest() ) @@ -6273,6 +6326,7 @@ def test_create_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.create_model( request, @@ -6284,6 +6338,7 @@ def test_create_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_model_rest_bad_request(request_type=model_service.GetModelRequest): @@ -6394,10 +6449,13 @@ def test_get_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_get_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_get_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_get_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.GetModelRequest.pb(model_service.GetModelRequest()) transcode.return_value = { "method": "post", @@ -6419,6 +6477,7 @@ def test_get_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.get_model( request, @@ -6430,6 +6489,7 @@ def test_get_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_pause_model_rest_bad_request(request_type=model_service.PauseModelRequest): @@ -6540,10 +6600,13 @@ def test_pause_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_pause_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_pause_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_pause_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.PauseModelRequest.pb( model_service.PauseModelRequest() ) @@ -6567,6 +6630,7 @@ def test_pause_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.pause_model( request, @@ -6578,6 +6642,7 @@ def test_pause_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_model_rest_bad_request(request_type=model_service.ResumeModelRequest): @@ -6688,10 +6753,13 @@ def test_resume_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_resume_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_resume_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_resume_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ResumeModelRequest.pb( model_service.ResumeModelRequest() ) @@ -6715,6 +6783,7 @@ def test_resume_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model.Model() + post_with_metadata.return_value = model.Model(), metadata client.resume_model( request, @@ -6726,6 +6795,7 @@ def test_resume_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_model_rest_bad_request(request_type=model_service.DeleteModelRequest): @@ -6919,10 +6989,13 @@ def test_list_models_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_list_models" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_list_models_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_list_models" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.ListModelsRequest.pb( model_service.ListModelsRequest() ) @@ -6948,6 +7021,7 @@ def test_list_models_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = model_service.ListModelsResponse() + post_with_metadata.return_value = model_service.ListModelsResponse(), metadata client.list_models( request, @@ -6959,6 +7033,7 @@ def test_list_models_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_model_rest_bad_request(request_type=model_service.UpdateModelRequest): @@ -7166,10 +7241,13 @@ def test_update_model_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ModelServiceRestInterceptor, "post_update_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_update_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_update_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.UpdateModelRequest.pb( model_service.UpdateModelRequest() ) @@ -7193,6 +7271,7 @@ def test_update_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_model.Model() + post_with_metadata.return_value = gcr_model.Model(), metadata client.update_model( request, @@ -7204,6 +7283,7 @@ def test_update_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_tune_model_rest_bad_request(request_type=model_service.TuneModelRequest): @@ -7286,10 +7366,13 @@ def test_tune_model_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ModelServiceRestInterceptor, "post_tune_model" ) as post, mock.patch.object( + transports.ModelServiceRestInterceptor, "post_tune_model_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ModelServiceRestInterceptor, "pre_tune_model" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = model_service.TuneModelRequest.pb(model_service.TuneModelRequest()) transcode.return_value = { "method": "post", @@ -7311,6 +7394,7 @@ def test_tune_model_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.tune_model( request, @@ -7322,6 +7406,7 @@ def test_tune_model_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_prediction_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_prediction_service.py index ade44114cd6a..c505915cf9ff 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_prediction_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_prediction_service.py @@ -72,6 +72,13 @@ user_event, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = PredictionServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1753,10 +1803,13 @@ def test_predict_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.PredictionServiceRestInterceptor, "post_predict" ) as post, mock.patch.object( + transports.PredictionServiceRestInterceptor, "post_predict_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.PredictionServiceRestInterceptor, "pre_predict" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = prediction_service.PredictRequest.pb( prediction_service.PredictRequest() ) @@ -1782,6 +1835,7 @@ def test_predict_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = prediction_service.PredictResponse() + post_with_metadata.return_value = prediction_service.PredictResponse(), metadata client.predict( request, @@ -1793,6 +1847,7 @@ def test_predict_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_product_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_product_service.py index ff8091532968..0301963f11e6 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_product_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_product_service.py @@ -79,6 +79,13 @@ from google.cloud.retail_v2beta.types import product from google.cloud.retail_v2beta.types import product as gcr_product +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -337,6 +344,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProductServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -9047,10 +9097,13 @@ def test_create_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_create_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_create_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_create_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.CreateProductRequest.pb( product_service.CreateProductRequest() ) @@ -9074,6 +9127,7 @@ def test_create_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.create_product( request, @@ -9085,6 +9139,7 @@ def test_create_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_product_rest_bad_request(request_type=product_service.GetProductRequest): @@ -9205,10 +9260,13 @@ def test_get_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_get_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_get_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_get_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.GetProductRequest.pb( product_service.GetProductRequest() ) @@ -9232,6 +9290,7 @@ def test_get_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product.Product() + post_with_metadata.return_value = product.Product(), metadata client.get_product( request, @@ -9243,6 +9302,7 @@ def test_get_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_products_rest_bad_request( @@ -9331,10 +9391,13 @@ def test_list_products_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_list_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_list_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_list_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.ListProductsRequest.pb( product_service.ListProductsRequest() ) @@ -9360,6 +9423,10 @@ def test_list_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = product_service.ListProductsResponse() + post_with_metadata.return_value = ( + product_service.ListProductsResponse(), + metadata, + ) client.list_products( request, @@ -9371,6 +9438,7 @@ def test_list_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_product_rest_bad_request( @@ -9644,10 +9712,13 @@ def test_update_product_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProductServiceRestInterceptor, "post_update_product" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_update_product_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_update_product" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.UpdateProductRequest.pb( product_service.UpdateProductRequest() ) @@ -9671,6 +9742,7 @@ def test_update_product_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_product.Product() + post_with_metadata.return_value = gcr_product.Product(), metadata client.update_product( request, @@ -9682,6 +9754,7 @@ def test_update_product_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_product_rest_bad_request( @@ -9879,10 +9952,13 @@ def test_purge_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_purge_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_purge_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_purge_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeProductsRequest.pb( purge_config.PurgeProductsRequest() ) @@ -9906,6 +9982,7 @@ def test_purge_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_products( request, @@ -9917,6 +9994,7 @@ def test_purge_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_products_rest_bad_request( @@ -10001,10 +10079,13 @@ def test_import_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_import_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_import_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_import_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportProductsRequest.pb( import_config.ImportProductsRequest() ) @@ -10028,6 +10109,7 @@ def test_import_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_products( request, @@ -10039,6 +10121,7 @@ def test_import_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_products_rest_bad_request( @@ -10123,10 +10206,13 @@ def test_export_products_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_export_products" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_export_products_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_export_products" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportProductsRequest.pb( export_config.ExportProductsRequest() ) @@ -10150,6 +10236,7 @@ def test_export_products_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_products( request, @@ -10161,6 +10248,7 @@ def test_export_products_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_set_inventory_rest_bad_request( @@ -10249,10 +10337,13 @@ def test_set_inventory_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_set_inventory" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, "post_set_inventory_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_set_inventory" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.SetInventoryRequest.pb( product_service.SetInventoryRequest() ) @@ -10276,6 +10367,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.set_inventory( request, @@ -10287,6 +10379,7 @@ def test_set_inventory_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_fulfillment_places_rest_bad_request( @@ -10371,10 +10464,14 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddFulfillmentPlacesRequest.pb( product_service.AddFulfillmentPlacesRequest() ) @@ -10398,6 +10495,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_fulfillment_places( request, @@ -10409,6 +10507,7 @@ def test_add_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_fulfillment_places_rest_bad_request( @@ -10493,10 +10592,14 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_fulfillment_places" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_fulfillment_places_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_fulfillment_places" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveFulfillmentPlacesRequest.pb( product_service.RemoveFulfillmentPlacesRequest() ) @@ -10520,6 +10623,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_fulfillment_places( request, @@ -10531,6 +10635,7 @@ def test_remove_fulfillment_places_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_local_inventories_rest_bad_request( @@ -10615,10 +10720,14 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_add_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_add_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_add_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.AddLocalInventoriesRequest.pb( product_service.AddLocalInventoriesRequest() ) @@ -10642,6 +10751,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.add_local_inventories( request, @@ -10653,6 +10763,7 @@ def test_add_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_local_inventories_rest_bad_request( @@ -10737,10 +10848,14 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ), mock.patch.object( transports.ProductServiceRestInterceptor, "post_remove_local_inventories" ) as post, mock.patch.object( + transports.ProductServiceRestInterceptor, + "post_remove_local_inventories_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProductServiceRestInterceptor, "pre_remove_local_inventories" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = product_service.RemoveLocalInventoriesRequest.pb( product_service.RemoveLocalInventoriesRequest() ) @@ -10764,6 +10879,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.remove_local_inventories( request, @@ -10775,6 +10891,7 @@ def test_remove_local_inventories_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_project_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_project_service.py index 5193d6609cc5..d45ff8280cd8 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_project_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_project_service.py @@ -62,6 +62,13 @@ ) from google.cloud.retail_v2beta.types import project, project_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -320,6 +327,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ProjectServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ProjectServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -2396,10 +2446,13 @@ def test_get_alert_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_get_alert_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, "post_get_alert_config_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_get_alert_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.GetAlertConfigRequest.pb( project_service.GetAlertConfigRequest() ) @@ -2423,6 +2476,7 @@ def test_get_alert_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.AlertConfig() + post_with_metadata.return_value = project.AlertConfig(), metadata client.get_alert_config( request, @@ -2434,6 +2488,7 @@ def test_get_alert_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_alert_config_rest_bad_request( @@ -2595,10 +2650,14 @@ def test_update_alert_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ProjectServiceRestInterceptor, "post_update_alert_config" ) as post, mock.patch.object( + transports.ProjectServiceRestInterceptor, + "post_update_alert_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ProjectServiceRestInterceptor, "pre_update_alert_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = project_service.UpdateAlertConfigRequest.pb( project_service.UpdateAlertConfigRequest() ) @@ -2622,6 +2681,7 @@ def test_update_alert_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = project.AlertConfig() + post_with_metadata.return_value = project.AlertConfig(), metadata client.update_alert_config( request, @@ -2633,6 +2693,7 @@ def test_update_alert_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_search_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_search_service.py index 71ef3e5141bd..e1936fdeab1f 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_search_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_search_service.py @@ -62,6 +62,13 @@ ) from google.cloud.retail_v2beta.types import common, search_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -316,6 +323,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = SearchServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -1999,10 +2049,13 @@ def test_search_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.SearchServiceRestInterceptor, "post_search" ) as post, mock.patch.object( + transports.SearchServiceRestInterceptor, "post_search_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.SearchServiceRestInterceptor, "pre_search" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = search_service.SearchRequest.pb(search_service.SearchRequest()) transcode.return_value = { "method": "post", @@ -2026,6 +2079,7 @@ def test_search_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = search_service.SearchResponse() + post_with_metadata.return_value = search_service.SearchResponse(), metadata client.search( request, @@ -2037,6 +2091,7 @@ def test_search_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_serving_config_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_serving_config_service.py index 109369ff5750..7582058d9a49 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_serving_config_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_serving_config_service.py @@ -66,6 +66,13 @@ from google.cloud.retail_v2beta.types import serving_config from google.cloud.retail_v2beta.types import serving_config_service +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -339,6 +346,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = ServingConfigServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6318,10 +6368,14 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_create_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_create_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_create_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.CreateServingConfigRequest.pb( serving_config_service.CreateServingConfigRequest() ) @@ -6347,6 +6401,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.create_serving_config( request, @@ -6358,6 +6413,7 @@ def test_create_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_serving_config_rest_bad_request( @@ -6714,10 +6770,14 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_update_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_update_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_update_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.UpdateServingConfigRequest.pb( serving_config_service.UpdateServingConfigRequest() ) @@ -6743,6 +6803,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.update_serving_config( request, @@ -6754,6 +6815,7 @@ def test_update_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_serving_config_rest_bad_request( @@ -6881,10 +6943,14 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_get_serving_config" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_get_serving_config_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_get_serving_config" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.GetServingConfigRequest.pb( serving_config_service.GetServingConfigRequest() ) @@ -6910,6 +6976,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config.ServingConfig() + post_with_metadata.return_value = serving_config.ServingConfig(), metadata client.get_serving_config( request, @@ -6921,6 +6988,7 @@ def test_get_serving_config_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_list_serving_configs_rest_bad_request( @@ -7007,10 +7075,14 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_list_serving_configs" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_list_serving_configs_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_list_serving_configs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.ListServingConfigsRequest.pb( serving_config_service.ListServingConfigsRequest() ) @@ -7036,6 +7108,10 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = serving_config_service.ListServingConfigsResponse() + post_with_metadata.return_value = ( + serving_config_service.ListServingConfigsResponse(), + metadata, + ) client.list_serving_configs( request, @@ -7047,6 +7123,7 @@ def test_list_serving_configs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_add_control_rest_bad_request( @@ -7174,10 +7251,13 @@ def test_add_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_add_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, "post_add_control_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_add_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.AddControlRequest.pb( serving_config_service.AddControlRequest() ) @@ -7203,6 +7283,7 @@ def test_add_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.add_control( request, @@ -7214,6 +7295,7 @@ def test_add_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_remove_control_rest_bad_request( @@ -7341,10 +7423,14 @@ def test_remove_control_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "post_remove_control" ) as post, mock.patch.object( + transports.ServingConfigServiceRestInterceptor, + "post_remove_control_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.ServingConfigServiceRestInterceptor, "pre_remove_control" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = serving_config_service.RemoveControlRequest.pb( serving_config_service.RemoveControlRequest() ) @@ -7370,6 +7456,7 @@ def test_remove_control_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcr_serving_config.ServingConfig() + post_with_metadata.return_value = gcr_serving_config.ServingConfig(), metadata client.remove_control( request, @@ -7381,6 +7468,7 @@ def test_remove_control_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_user_event_service.py b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_user_event_service.py index 238d613d31b9..b8e05fb7da8c 100644 --- a/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_user_event_service.py +++ b/packages/google-cloud-retail/tests/unit/gapic/retail_v2beta/test_user_event_service.py @@ -86,6 +86,13 @@ user_event_service, ) +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -345,6 +352,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = UserEventServiceClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -4291,10 +4341,14 @@ def test_write_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_write_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_write_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_write_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.WriteUserEventRequest.pb( user_event_service.WriteUserEventRequest() ) @@ -4318,6 +4372,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = user_event.UserEvent() + post_with_metadata.return_value = user_event.UserEvent(), metadata client.write_user_event( request, @@ -4329,6 +4384,7 @@ def test_write_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_collect_user_event_rest_bad_request( @@ -4412,10 +4468,14 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.UserEventServiceRestInterceptor, "post_collect_user_event" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_collect_user_event_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_collect_user_event" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.CollectUserEventRequest.pb( user_event_service.CollectUserEventRequest() ) @@ -4439,6 +4499,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = httpbody_pb2.HttpBody() + post_with_metadata.return_value = httpbody_pb2.HttpBody(), metadata client.collect_user_event( request, @@ -4450,6 +4511,7 @@ def test_collect_user_event_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_purge_user_events_rest_bad_request( @@ -4530,10 +4592,14 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_purge_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_purge_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_purge_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = purge_config.PurgeUserEventsRequest.pb( purge_config.PurgeUserEventsRequest() ) @@ -4557,6 +4623,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.purge_user_events( request, @@ -4568,6 +4635,7 @@ def test_purge_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_import_user_events_rest_bad_request( @@ -4648,10 +4716,14 @@ def test_import_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_import_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_import_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_import_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = import_config.ImportUserEventsRequest.pb( import_config.ImportUserEventsRequest() ) @@ -4675,6 +4747,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.import_user_events( request, @@ -4686,6 +4759,7 @@ def test_import_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_export_user_events_rest_bad_request( @@ -4766,10 +4840,14 @@ def test_export_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_export_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_export_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_export_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = export_config.ExportUserEventsRequest.pb( export_config.ExportUserEventsRequest() ) @@ -4793,6 +4871,7 @@ def test_export_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.export_user_events( request, @@ -4804,6 +4883,7 @@ def test_export_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_rejoin_user_events_rest_bad_request( @@ -4884,10 +4964,14 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ), mock.patch.object( transports.UserEventServiceRestInterceptor, "post_rejoin_user_events" ) as post, mock.patch.object( + transports.UserEventServiceRestInterceptor, + "post_rejoin_user_events_with_metadata", + ) as post_with_metadata, mock.patch.object( transports.UserEventServiceRestInterceptor, "pre_rejoin_user_events" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = user_event_service.RejoinUserEventsRequest.pb( user_event_service.RejoinUserEventsRequest() ) @@ -4911,6 +4995,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata client.rejoin_user_events( request, @@ -4922,6 +5007,7 @@ def test_rejoin_user_events_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_operation_rest_bad_request( diff --git a/packages/google-cloud-scheduler/README.rst b/packages/google-cloud-scheduler/README.rst index 4fce1a729991..83b16f6878ce 100644 --- a/packages/google-cloud-scheduler/README.rst +++ b/packages/google-cloud-scheduler/README.rst @@ -26,12 +26,12 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ 3. `Enable the Cloud Scheduler.`_ -4. `Setup Authentication.`_ +4. `Set up Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Cloud Scheduler.: https://cloud.google.com/scheduler/docs -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Set up Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py index c7d2e6b06092..558c8aab67c5 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.15.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py index c7d2e6b06092..558c8aab67c5 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.15.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/client.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/client.py index d7f28c98da7b..79c21b4b8fb6 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/client.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -513,6 +515,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1680,16 +1709,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -1735,16 +1768,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/transports/rest.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/transports/rest.py index fef2ec30ce34..a102d1769616 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/transports/rest.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/services/cloud_scheduler/transports/rest.py @@ -156,12 +156,33 @@ def pre_create_job( def post_create_job(self, response: gcs_job.Job) -> gcs_job.Job: """Post-rpc interceptor for create_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_create_job` interceptor runs + before the `post_create_job_with_metadata` interceptor. """ return response + def post_create_job_with_metadata( + self, response: gcs_job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[gcs_job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_create_job_with_metadata` + interceptor in new development instead of the `post_create_job` interceptor. + When both interceptors are used, this `post_create_job_with_metadata` interceptor runs after the + `post_create_job` interceptor. The (possibly modified) response returned by + `post_create_job` will be passed to + `post_create_job_with_metadata`. + """ + return response, metadata + def pre_delete_job( self, request: cloudscheduler.DeleteJobRequest, @@ -191,12 +212,33 @@ def pre_get_job( def post_get_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for get_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_get_job` interceptor runs + before the `post_get_job_with_metadata` interceptor. """ return response + def post_get_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_get_job_with_metadata` + interceptor in new development instead of the `post_get_job` interceptor. + When both interceptors are used, this `post_get_job_with_metadata` interceptor runs after the + `post_get_job` interceptor. The (possibly modified) response returned by + `post_get_job` will be passed to + `post_get_job_with_metadata`. + """ + return response, metadata + def pre_list_jobs( self, request: cloudscheduler.ListJobsRequest, @@ -214,12 +256,37 @@ def post_list_jobs( ) -> cloudscheduler.ListJobsResponse: """Post-rpc interceptor for list_jobs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_jobs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_list_jobs` interceptor runs + before the `post_list_jobs_with_metadata` interceptor. """ return response + def post_list_jobs_with_metadata( + self, + response: cloudscheduler.ListJobsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudscheduler.ListJobsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_jobs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_list_jobs_with_metadata` + interceptor in new development instead of the `post_list_jobs` interceptor. + When both interceptors are used, this `post_list_jobs_with_metadata` interceptor runs after the + `post_list_jobs` interceptor. The (possibly modified) response returned by + `post_list_jobs` will be passed to + `post_list_jobs_with_metadata`. + """ + return response, metadata + def pre_pause_job( self, request: cloudscheduler.PauseJobRequest, @@ -235,12 +302,33 @@ def pre_pause_job( def post_pause_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for pause_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_pause_job` interceptor runs + before the `post_pause_job_with_metadata` interceptor. """ return response + def post_pause_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_pause_job_with_metadata` + interceptor in new development instead of the `post_pause_job` interceptor. + When both interceptors are used, this `post_pause_job_with_metadata` interceptor runs after the + `post_pause_job` interceptor. The (possibly modified) response returned by + `post_pause_job` will be passed to + `post_pause_job_with_metadata`. + """ + return response, metadata + def pre_resume_job( self, request: cloudscheduler.ResumeJobRequest, @@ -258,12 +346,33 @@ def pre_resume_job( def post_resume_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for resume_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_resume_job` interceptor runs + before the `post_resume_job_with_metadata` interceptor. """ return response + def post_resume_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_resume_job_with_metadata` + interceptor in new development instead of the `post_resume_job` interceptor. + When both interceptors are used, this `post_resume_job_with_metadata` interceptor runs after the + `post_resume_job` interceptor. The (possibly modified) response returned by + `post_resume_job` will be passed to + `post_resume_job_with_metadata`. + """ + return response, metadata + def pre_run_job( self, request: cloudscheduler.RunJobRequest, @@ -279,12 +388,33 @@ def pre_run_job( def post_run_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for run_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_run_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_run_job` interceptor runs + before the `post_run_job_with_metadata` interceptor. """ return response + def post_run_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for run_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_run_job_with_metadata` + interceptor in new development instead of the `post_run_job` interceptor. + When both interceptors are used, this `post_run_job_with_metadata` interceptor runs after the + `post_run_job` interceptor. The (possibly modified) response returned by + `post_run_job` will be passed to + `post_run_job_with_metadata`. + """ + return response, metadata + def pre_update_job( self, request: cloudscheduler.UpdateJobRequest, @@ -302,12 +432,33 @@ def pre_update_job( def post_update_job(self, response: gcs_job.Job) -> gcs_job.Job: """Post-rpc interceptor for update_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_update_job` interceptor runs + before the `post_update_job_with_metadata` interceptor. """ return response + def post_update_job_with_metadata( + self, response: gcs_job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[gcs_job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_update_job_with_metadata` + interceptor in new development instead of the `post_update_job` interceptor. + When both interceptors are used, this `post_update_job_with_metadata` interceptor runs after the + `post_update_job` interceptor. The (possibly modified) response returned by + `post_update_job` will be passed to + `post_update_job_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -579,6 +730,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -836,6 +991,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -983,6 +1142,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_jobs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_jobs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1139,6 +1302,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1295,6 +1462,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1447,6 +1618,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_run_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_run_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1603,6 +1778,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py index c7d2e6b06092..558c8aab67c5 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.15.1" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py index 2c83170454b9..36127543a343 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py @@ -14,6 +14,8 @@ # limitations under the License. # from collections import OrderedDict +from http import HTTPStatus +import json import logging as std_logging import os import re @@ -512,6 +514,33 @@ def _validate_universe_domain(self): # NOTE (b/349488459): universe validation is disabled until further notice. return True + def _add_cred_info_for_auth_errors( + self, error: core_exceptions.GoogleAPICallError + ) -> None: + """Adds credential info string to error details for 401/403/404 errors. + + Args: + error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info. + """ + if error.code not in [ + HTTPStatus.UNAUTHORIZED, + HTTPStatus.FORBIDDEN, + HTTPStatus.NOT_FOUND, + ]: + return + + cred = self._transport._credentials + + # get_cred_info is only available in google-auth>=2.35.0 + if not hasattr(cred, "get_cred_info"): + return + + # ignore the type check since pypy test fails when get_cred_info + # is not available + cred_info = cred.get_cred_info() # type: ignore + if cred_info and hasattr(error._details, "append"): + error._details.append(json.dumps(cred_info)) + @property def api_endpoint(self): """Return the API endpoint used by the client instance. @@ -1680,16 +1709,20 @@ def get_location( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e def list_locations( self, @@ -1735,16 +1768,20 @@ def list_locations( # Validate the universe domain. self._validate_universe_domain() - # Send the request. - response = rpc( - request, - retry=retry, - timeout=timeout, - metadata=metadata, - ) + try: + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) - # Done; return the response. - return response + # Done; return the response. + return response + except core_exceptions.GoogleAPICallError as e: + self._add_cred_info_for_auth_errors(e) + raise e DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/rest.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/rest.py index 197c0e5f2d3e..209a7badaf68 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/rest.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/rest.py @@ -155,12 +155,33 @@ def pre_create_job( def post_create_job(self, response: gcs_job.Job) -> gcs_job.Job: """Post-rpc interceptor for create_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_create_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_create_job` interceptor runs + before the `post_create_job_with_metadata` interceptor. """ return response + def post_create_job_with_metadata( + self, response: gcs_job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[gcs_job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for create_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_create_job_with_metadata` + interceptor in new development instead of the `post_create_job` interceptor. + When both interceptors are used, this `post_create_job_with_metadata` interceptor runs after the + `post_create_job` interceptor. The (possibly modified) response returned by + `post_create_job` will be passed to + `post_create_job_with_metadata`. + """ + return response, metadata + def pre_delete_job( self, request: cloudscheduler.DeleteJobRequest, @@ -190,12 +211,33 @@ def pre_get_job( def post_get_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for get_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_get_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_get_job` interceptor runs + before the `post_get_job_with_metadata` interceptor. """ return response + def post_get_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for get_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_get_job_with_metadata` + interceptor in new development instead of the `post_get_job` interceptor. + When both interceptors are used, this `post_get_job_with_metadata` interceptor runs after the + `post_get_job` interceptor. The (possibly modified) response returned by + `post_get_job` will be passed to + `post_get_job_with_metadata`. + """ + return response, metadata + def pre_list_jobs( self, request: cloudscheduler.ListJobsRequest, @@ -213,12 +255,37 @@ def post_list_jobs( ) -> cloudscheduler.ListJobsResponse: """Post-rpc interceptor for list_jobs - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_list_jobs_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_list_jobs` interceptor runs + before the `post_list_jobs_with_metadata` interceptor. """ return response + def post_list_jobs_with_metadata( + self, + response: cloudscheduler.ListJobsResponse, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + cloudscheduler.ListJobsResponse, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Post-rpc interceptor for list_jobs + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_list_jobs_with_metadata` + interceptor in new development instead of the `post_list_jobs` interceptor. + When both interceptors are used, this `post_list_jobs_with_metadata` interceptor runs after the + `post_list_jobs` interceptor. The (possibly modified) response returned by + `post_list_jobs` will be passed to + `post_list_jobs_with_metadata`. + """ + return response, metadata + def pre_pause_job( self, request: cloudscheduler.PauseJobRequest, @@ -234,12 +301,33 @@ def pre_pause_job( def post_pause_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for pause_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_pause_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_pause_job` interceptor runs + before the `post_pause_job_with_metadata` interceptor. """ return response + def post_pause_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for pause_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_pause_job_with_metadata` + interceptor in new development instead of the `post_pause_job` interceptor. + When both interceptors are used, this `post_pause_job_with_metadata` interceptor runs after the + `post_pause_job` interceptor. The (possibly modified) response returned by + `post_pause_job` will be passed to + `post_pause_job_with_metadata`. + """ + return response, metadata + def pre_resume_job( self, request: cloudscheduler.ResumeJobRequest, @@ -257,12 +345,33 @@ def pre_resume_job( def post_resume_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for resume_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_resume_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_resume_job` interceptor runs + before the `post_resume_job_with_metadata` interceptor. """ return response + def post_resume_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for resume_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_resume_job_with_metadata` + interceptor in new development instead of the `post_resume_job` interceptor. + When both interceptors are used, this `post_resume_job_with_metadata` interceptor runs after the + `post_resume_job` interceptor. The (possibly modified) response returned by + `post_resume_job` will be passed to + `post_resume_job_with_metadata`. + """ + return response, metadata + def pre_run_job( self, request: cloudscheduler.RunJobRequest, @@ -278,12 +387,33 @@ def pre_run_job( def post_run_job(self, response: job.Job) -> job.Job: """Post-rpc interceptor for run_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_run_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_run_job` interceptor runs + before the `post_run_job_with_metadata` interceptor. """ return response + def post_run_job_with_metadata( + self, response: job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for run_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_run_job_with_metadata` + interceptor in new development instead of the `post_run_job` interceptor. + When both interceptors are used, this `post_run_job_with_metadata` interceptor runs after the + `post_run_job` interceptor. The (possibly modified) response returned by + `post_run_job` will be passed to + `post_run_job_with_metadata`. + """ + return response, metadata + def pre_update_job( self, request: cloudscheduler.UpdateJobRequest, @@ -301,12 +431,33 @@ def pre_update_job( def post_update_job(self, response: gcs_job.Job) -> gcs_job.Job: """Post-rpc interceptor for update_job - Override in a subclass to manipulate the response + DEPRECATED. Please use the `post_update_job_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response after it is returned by the CloudScheduler server but before - it is returned to user code. + it is returned to user code. This `post_update_job` interceptor runs + before the `post_update_job_with_metadata` interceptor. """ return response + def post_update_job_with_metadata( + self, response: gcs_job.Job, metadata: Sequence[Tuple[str, Union[str, bytes]]] + ) -> Tuple[gcs_job.Job, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for update_job + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the CloudScheduler server but before it is returned to user code. + + We recommend only using this `post_update_job_with_metadata` + interceptor in new development instead of the `post_update_job` interceptor. + When both interceptors are used, this `post_update_job_with_metadata` interceptor runs after the + `post_update_job` interceptor. The (possibly modified) response returned by + `post_update_job` will be passed to + `post_update_job_with_metadata`. + """ + return response, metadata + def pre_get_location( self, request: locations_pb2.GetLocationRequest, @@ -578,6 +729,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_create_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_create_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -835,6 +990,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_get_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_get_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -982,6 +1141,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_list_jobs(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_list_jobs_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1138,6 +1301,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_pause_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_pause_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1294,6 +1461,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_resume_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_resume_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1446,6 +1617,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_run_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_run_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER @@ -1602,6 +1777,10 @@ def __call__( json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) resp = self._interceptor.post_update_job(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_update_job_with_metadata( + resp, response_metadata + ) if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( logging.DEBUG ): # pragma: NO COVER diff --git a/packages/google-cloud-scheduler/noxfile.py b/packages/google-cloud-scheduler/noxfile.py index a9ceef47133c..0acc836b384e 100644 --- a/packages/google-cloud-scheduler/noxfile.py +++ b/packages/google-cloud-scheduler/noxfile.py @@ -382,20 +382,29 @@ def docfx(session): ["python", "upb", "cpp"], ) def prerelease_deps(session, protobuf_implementation): - """Run all tests with prerelease versions of dependencies installed.""" + """ + Run all tests with pre-release versions of dependencies installed + rather than the standard non pre-release versions. + Pre-releases versions can be installed using + `pip install --pre `. + """ if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies - session.install("-e", ".[all, tests, tracing]") + session.install("-e", ".") + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + # Install dependencies for the unit test environment session.install(*unit_deps_all) + system_deps_all = ( SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + SYSTEM_TEST_EXTRAS ) + # Install dependencies for the system test environment session.install(*system_deps_all) # Because we test minimum dependency versions on the minimum Python @@ -417,6 +426,7 @@ def prerelease_deps(session, protobuf_implementation): ) ] + # Install dependencies specified in `testing/constraints-X.txt`. session.install(*constraints_deps) prerel_deps = [ @@ -458,3 +468,70 @@ def prerelease_deps(session, protobuf_implementation): "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, ) + + +@nox.session(python="3.13") +@nox.parametrize( + "protobuf_implementation", + ["python", "upb"], +) +def core_deps_from_source(session, protobuf_implementation): + """Run all tests with local versions of core dependencies installed, + rather than pulling core dependencies from PyPI. + """ + + # Install all dependencies + session.install(".") + + # Install dependencies for the unit test environment + unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES + session.install(*unit_deps_all) + + # Install dependencies for the system test environment + system_deps_all = ( + SYSTEM_TEST_STANDARD_DEPENDENCIES + + SYSTEM_TEST_EXTERNAL_DEPENDENCIES + + SYSTEM_TEST_EXTRAS + ) + session.install(*system_deps_all) + + # Because we test minimum dependency versions on the minimum Python + # version, the first version we test with in the unit tests sessions has a + # constraints file containing all dependencies and extras that should be installed. + with open( + CURRENT_DIRECTORY + / "testing" + / f"constraints-{UNIT_TEST_PYTHON_VERSIONS[0]}.txt", + encoding="utf-8", + ) as constraints_file: + constraints_text = constraints_file.read() + + # Ignore leading whitespace and comment lines. + constraints_deps = [ + match.group(1) + for match in re.finditer( + r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE + ) + ] + + # Install dependencies specified in `testing/constraints-X.txt`. + session.install(*constraints_deps) + + core_dependencies_from_source = [ + "google-api-core @ git+https://github.com/googleapis/python-api-core.git", + "google-auth @ git+https://github.com/googleapis/google-auth-library-python.git", + f"{CURRENT_DIRECTORY}/../googleapis-common-protos", + f"{CURRENT_DIRECTORY}/../grpc-google-iam-v1", + "proto-plus @ git+https://github.com/googleapis/proto-plus-python.git", + ] + + for dep in core_dependencies_from_source: + session.install(dep, "--ignore-installed", "--no-deps") + + session.run( + "py.test", + "tests/unit", + env={ + "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, + }, + ) diff --git a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json index 1a12f734ce1e..150f660ac6a2 100644 --- a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json +++ b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-scheduler", - "version": "2.15.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json index 945351ab6925..579bee0411e1 100644 --- a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json +++ b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-scheduler", - "version": "2.15.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py b/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py index 616553b33b5b..483256444eb6 100644 --- a/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py +++ b/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py @@ -70,6 +70,13 @@ from google.cloud.scheduler_v1.types import job as gcs_job from google.cloud.scheduler_v1.types import target +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -328,6 +335,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudSchedulerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudSchedulerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6009,10 +6059,13 @@ def test_list_jobs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_list_jobs" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_list_jobs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_list_jobs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.ListJobsRequest.pb(cloudscheduler.ListJobsRequest()) transcode.return_value = { "method": "post", @@ -6036,6 +6089,7 @@ def test_list_jobs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudscheduler.ListJobsResponse() + post_with_metadata.return_value = cloudscheduler.ListJobsResponse(), metadata client.list_jobs( request, @@ -6047,6 +6101,7 @@ def test_list_jobs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_job_rest_bad_request(request_type=cloudscheduler.GetJobRequest): @@ -6137,10 +6192,13 @@ def test_get_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_get_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_get_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_get_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.GetJobRequest.pb(cloudscheduler.GetJobRequest()) transcode.return_value = { "method": "post", @@ -6162,6 +6220,7 @@ def test_get_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.get_job( request, @@ -6173,6 +6232,7 @@ def test_get_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_job_rest_bad_request(request_type=cloudscheduler.CreateJobRequest): @@ -6389,10 +6449,13 @@ def test_create_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_create_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_create_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_create_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.CreateJobRequest.pb( cloudscheduler.CreateJobRequest() ) @@ -6416,6 +6479,7 @@ def test_create_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcs_job.Job() + post_with_metadata.return_value = gcs_job.Job(), metadata client.create_job( request, @@ -6427,6 +6491,7 @@ def test_create_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_job_rest_bad_request(request_type=cloudscheduler.UpdateJobRequest): @@ -6643,10 +6708,13 @@ def test_update_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_update_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_update_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_update_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.UpdateJobRequest.pb( cloudscheduler.UpdateJobRequest() ) @@ -6670,6 +6738,7 @@ def test_update_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcs_job.Job() + post_with_metadata.return_value = gcs_job.Job(), metadata client.update_job( request, @@ -6681,6 +6750,7 @@ def test_update_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_job_rest_bad_request(request_type=cloudscheduler.DeleteJobRequest): @@ -6878,10 +6948,13 @@ def test_pause_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_pause_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_pause_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_pause_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.PauseJobRequest.pb(cloudscheduler.PauseJobRequest()) transcode.return_value = { "method": "post", @@ -6903,6 +6976,7 @@ def test_pause_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.pause_job( request, @@ -6914,6 +6988,7 @@ def test_pause_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_job_rest_bad_request(request_type=cloudscheduler.ResumeJobRequest): @@ -7004,10 +7079,13 @@ def test_resume_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_resume_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_resume_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_resume_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.ResumeJobRequest.pb( cloudscheduler.ResumeJobRequest() ) @@ -7031,6 +7109,7 @@ def test_resume_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.resume_job( request, @@ -7042,6 +7121,7 @@ def test_resume_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_run_job_rest_bad_request(request_type=cloudscheduler.RunJobRequest): @@ -7132,10 +7212,13 @@ def test_run_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_run_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_run_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_run_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.RunJobRequest.pb(cloudscheduler.RunJobRequest()) transcode.return_value = { "method": "post", @@ -7157,6 +7240,7 @@ def test_run_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.run_job( request, @@ -7168,6 +7252,7 @@ def test_run_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): diff --git a/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py b/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py index d7837853eb7c..4f21618e2b98 100644 --- a/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py +++ b/packages/google-cloud-scheduler/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py @@ -69,6 +69,13 @@ from google.cloud.scheduler_v1beta1.types import job as gcs_job from google.cloud.scheduler_v1beta1.types import target +CRED_INFO_JSON = { + "credential_source": "/path/to/file", + "credential_type": "service account credentials", + "principal": "service-account@example.com", +} +CRED_INFO_STRING = json.dumps(CRED_INFO_JSON) + async def mock_async_gen(data, chunk_size=1): for i in range(0, len(data)): # pragma: NO COVER @@ -327,6 +334,49 @@ def test__get_universe_domain(): assert str(excinfo.value) == "Universe Domain cannot be an empty string." +@pytest.mark.parametrize( + "error_code,cred_info_json,show_cred_info", + [ + (401, CRED_INFO_JSON, True), + (403, CRED_INFO_JSON, True), + (404, CRED_INFO_JSON, True), + (500, CRED_INFO_JSON, False), + (401, None, False), + (403, None, False), + (404, None, False), + (500, None, False), + ], +) +def test__add_cred_info_for_auth_errors(error_code, cred_info_json, show_cred_info): + cred = mock.Mock(["get_cred_info"]) + cred.get_cred_info = mock.Mock(return_value=cred_info_json) + client = CloudSchedulerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=["foo"]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + if show_cred_info: + assert error.details == ["foo", CRED_INFO_STRING] + else: + assert error.details == ["foo"] + + +@pytest.mark.parametrize("error_code", [401, 403, 404, 500]) +def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): + cred = mock.Mock([]) + assert not hasattr(cred, "get_cred_info") + client = CloudSchedulerClient(credentials=cred) + client._transport._credentials = cred + + error = core_exceptions.GoogleAPICallError("message", details=[]) + error.code = error_code + + client._add_cred_info_for_auth_errors(error) + assert error.details == [] + + @pytest.mark.parametrize( "client_class,transport_name", [ @@ -6049,10 +6099,13 @@ def test_list_jobs_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_list_jobs" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_list_jobs_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_list_jobs" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.ListJobsRequest.pb(cloudscheduler.ListJobsRequest()) transcode.return_value = { "method": "post", @@ -6076,6 +6129,7 @@ def test_list_jobs_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = cloudscheduler.ListJobsResponse() + post_with_metadata.return_value = cloudscheduler.ListJobsResponse(), metadata client.list_jobs( request, @@ -6087,6 +6141,7 @@ def test_list_jobs_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_job_rest_bad_request(request_type=cloudscheduler.GetJobRequest): @@ -6179,10 +6234,13 @@ def test_get_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_get_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_get_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_get_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.GetJobRequest.pb(cloudscheduler.GetJobRequest()) transcode.return_value = { "method": "post", @@ -6204,6 +6262,7 @@ def test_get_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.get_job( request, @@ -6215,6 +6274,7 @@ def test_get_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_create_job_rest_bad_request(request_type=cloudscheduler.CreateJobRequest): @@ -6434,10 +6494,13 @@ def test_create_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_create_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_create_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_create_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.CreateJobRequest.pb( cloudscheduler.CreateJobRequest() ) @@ -6461,6 +6524,7 @@ def test_create_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcs_job.Job() + post_with_metadata.return_value = gcs_job.Job(), metadata client.create_job( request, @@ -6472,6 +6536,7 @@ def test_create_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_update_job_rest_bad_request(request_type=cloudscheduler.UpdateJobRequest): @@ -6691,10 +6756,13 @@ def test_update_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_update_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_update_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_update_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.UpdateJobRequest.pb( cloudscheduler.UpdateJobRequest() ) @@ -6718,6 +6786,7 @@ def test_update_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = gcs_job.Job() + post_with_metadata.return_value = gcs_job.Job(), metadata client.update_job( request, @@ -6729,6 +6798,7 @@ def test_update_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_delete_job_rest_bad_request(request_type=cloudscheduler.DeleteJobRequest): @@ -6928,10 +6998,13 @@ def test_pause_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_pause_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_pause_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_pause_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.PauseJobRequest.pb(cloudscheduler.PauseJobRequest()) transcode.return_value = { "method": "post", @@ -6953,6 +7026,7 @@ def test_pause_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.pause_job( request, @@ -6964,6 +7038,7 @@ def test_pause_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_resume_job_rest_bad_request(request_type=cloudscheduler.ResumeJobRequest): @@ -7056,10 +7131,13 @@ def test_resume_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_resume_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_resume_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_resume_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.ResumeJobRequest.pb( cloudscheduler.ResumeJobRequest() ) @@ -7083,6 +7161,7 @@ def test_resume_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.resume_job( request, @@ -7094,6 +7173,7 @@ def test_resume_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_run_job_rest_bad_request(request_type=cloudscheduler.RunJobRequest): @@ -7186,10 +7266,13 @@ def test_run_job_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( transports.CloudSchedulerRestInterceptor, "post_run_job" ) as post, mock.patch.object( + transports.CloudSchedulerRestInterceptor, "post_run_job_with_metadata" + ) as post_with_metadata, mock.patch.object( transports.CloudSchedulerRestInterceptor, "pre_run_job" ) as pre: pre.assert_not_called() post.assert_not_called() + post_with_metadata.assert_not_called() pb_message = cloudscheduler.RunJobRequest.pb(cloudscheduler.RunJobRequest()) transcode.return_value = { "method": "post", @@ -7211,6 +7294,7 @@ def test_run_job_rest_interceptors(null_interceptor): ] pre.return_value = request, metadata post.return_value = job.Job() + post_with_metadata.return_value = job.Job(), metadata client.run_job( request, @@ -7222,6 +7306,7 @@ def test_run_job_rest_interceptors(null_interceptor): pre.assert_called_once() post.assert_called_once() + post_with_metadata.assert_called_once() def test_get_location_rest_bad_request(request_type=locations_pb2.GetLocationRequest): From 04a1a30536c108b912ac45482496929fddd7beea Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 18 Feb 2025 22:40:29 +0500 Subject: [PATCH 12/13] fix: ignore unittest.yml in renovate (#13537) See follow up issue https://github.com/googleapis/google-cloud-python/issues/13536 --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 13486b16f243..415d00201671 100644 --- a/renovate.json +++ b/renovate.json @@ -6,6 +6,7 @@ "schedule:weekly" ], "ignorePaths": [ - ".kokoro/docker/docs/requirements.txt" + ".kokoro/docker/docs/requirements.txt", + ".github/workflows/unittest.yml" ] } From d0f6afda90df75c96c3cb73c2d03a7670c4d62c4 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2025 10:52:56 -0800 Subject: [PATCH 13/13] chore: release main (#13521) :robot: I have created a release *beep* *boop* ---
google-cloud-alloydb: 0.4.3 ## [0.4.3](https://github.com/googleapis/google-cloud-python/compare/google-cloud-alloydb-v0.4.2...google-cloud-alloydb-v0.4.3) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-apigee-registry: 0.6.16 ## [0.6.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apigee-registry-v0.6.15...google-cloud-apigee-registry-v0.6.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-apphub: 0.1.7 ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apphub-v0.1.6...google-cloud-apphub-v0.1.7) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-artifact-registry: 1.15.1 ## [1.15.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-artifact-registry-v1.15.0...google-cloud-artifact-registry-v1.15.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-asset: 3.29.1 ## [3.29.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-asset-v3.29.0...google-cloud-asset-v3.29.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-automl: 2.16.1 ## [2.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-automl-v2.16.0...google-cloud-automl-v2.16.1) (2025-02-18) ### Bug Fixes * allow google-cloud-storage 3.x ([#13535](https://github.com/googleapis/google-cloud-python/issues/13535)) ([5dabf55](https://github.com/googleapis/google-cloud-python/commit/5dabf5556d505f55171344fd7c95384b8478e453))
google-cloud-backupdr: 0.2.2 ## [0.2.2](https://github.com/googleapis/google-cloud-python/compare/google-cloud-backupdr-v0.2.1...google-cloud-backupdr-v0.2.2) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bare-metal-solution: 1.10.1 ## [1.10.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bare-metal-solution-v1.10.0...google-cloud-bare-metal-solution-v1.10.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-beyondcorp-appconnections: 0.4.16 ## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnections-v0.4.15...google-cloud-beyondcorp-appconnections-v0.4.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-beyondcorp-appconnectors: 0.4.16 ## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnectors-v0.4.15...google-cloud-beyondcorp-appconnectors-v0.4.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-beyondcorp-appgateways: 0.4.16 ## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appgateways-v0.4.15...google-cloud-beyondcorp-appgateways-v0.4.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-beyondcorp-clientconnectorservices: 0.4.16 ## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientconnectorservices-v0.4.15...google-cloud-beyondcorp-clientconnectorservices-v0.4.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-beyondcorp-clientgateways: 0.4.15 ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientgateways-v0.4.14...google-cloud-beyondcorp-clientgateways-v0.4.15) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bigquery-analyticshub: 0.4.16 ## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-analyticshub-v0.4.15...google-cloud-bigquery-analyticshub-v0.4.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bigquery-connection: 1.18.1 ## [1.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-connection-v1.18.0...google-cloud-bigquery-connection-v1.18.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bigquery-data-exchange: 0.5.18 ## [0.5.18](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-data-exchange-v0.5.17...google-cloud-bigquery-data-exchange-v0.5.18) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bigquery-datapolicies: 0.6.13 ## [0.6.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-datapolicies-v0.6.12...google-cloud-bigquery-datapolicies-v0.6.13) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-bigquery-logging: 1.6.1 ## [1.6.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-logging-v1.6.0...google-cloud-bigquery-logging-v1.6.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-billing: 1.16.1 ## [1.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-billing-v1.16.0...google-cloud-billing-v1.16.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-build: 3.31.0 ## [3.31.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-build-v3.30.0...google-cloud-build-v3.31.0) (2025-02-18) ### Features * Add option to enable fetching dependencies ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) * Support for git proxy setup ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) ### Documentation * Updates to proto message comments ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18))
google-cloud-config: 0.1.16 ## [0.1.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-config-v0.1.15...google-cloud-config-v0.1.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-contact-center-insights: 1.23.1 ## [1.23.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contact-center-insights-v1.23.0...google-cloud-contact-center-insights-v1.23.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218))
google-cloud-containeranalysis: 2.17.1 ## [2.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-containeranalysis-v2.17.0...google-cloud-containeranalysis-v2.17.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-contentwarehouse: 0.7.14 ## [0.7.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contentwarehouse-v0.7.13...google-cloud-contentwarehouse-v0.7.14) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-data-fusion: 1.13.1 ## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-data-fusion-v1.13.0...google-cloud-data-fusion-v1.13.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-datacatalog: 3.25.1 ## [3.25.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datacatalog-v3.25.0...google-cloud-datacatalog-v3.25.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-dataform: 0.5.16 ## [0.5.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataform-v0.5.15...google-cloud-dataform-v0.5.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-dataplex: 2.7.1 ## [2.7.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataplex-v2.7.0...google-cloud-dataplex-v2.7.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-dataproc: 5.17.1 ## [5.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-v5.17.0...google-cloud-dataproc-v5.17.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-dataproc-metastore: 1.18.1 ## [1.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-metastore-v1.18.0...google-cloud-dataproc-metastore-v1.18.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-datastream: 1.13.1 ## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datastream-v1.13.0...google-cloud-datastream-v1.13.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-deploy: 2.6.1 ## [2.6.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-deploy-v2.6.0...google-cloud-deploy-v2.6.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-dms: 1.12.1 ## [1.12.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dms-v1.12.0...google-cloud-dms-v1.12.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-eventarc: 1.15.1 ## [1.15.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-eventarc-v1.15.0...google-cloud-eventarc-v1.15.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-functions: 1.20.1 ## [1.20.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-functions-v1.20.0...google-cloud-functions-v1.20.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-gke-backup: 0.5.16 ## [0.5.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-backup-v0.5.15...google-cloud-gke-backup-v0.5.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-gke-hub: 1.17.1 ## [1.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-hub-v1.17.0...google-cloud-gke-hub-v1.17.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-iam: 2.18.1 ## [2.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-v2.18.0...google-cloud-iam-v2.18.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-iam-logging: 1.4.1 ## [1.4.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-logging-v1.4.0...google-cloud-iam-logging-v1.4.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-iap: 1.16.1 ## [1.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iap-v1.16.0...google-cloud-iap-v1.16.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-kms: 3.3.1 ## [3.3.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-kms-v3.3.0...google-cloud-kms-v3.3.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-network-connectivity: 2.7.1 ## [2.7.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-connectivity-v2.7.0...google-cloud-network-connectivity-v2.7.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6))
google-cloud-network-management: 1.25.1 ## [1.25.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-management-v1.25.0...google-cloud-network-management-v1.25.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-network-security: 0.9.16 ## [0.9.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-security-v0.9.15...google-cloud-network-security-v0.9.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-network-services: 0.5.19 ## [0.5.19](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-services-v0.5.18...google-cloud-network-services-v0.5.19) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-notebooks: 1.13.1 ## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-notebooks-v1.13.0...google-cloud-notebooks-v1.13.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-parallelstore: 0.2.11 ## [0.2.11](https://github.com/googleapis/google-cloud-python/compare/google-cloud-parallelstore-v0.2.10...google-cloud-parallelstore-v0.2.11) (2025-02-18) ### Features * Adding `deployment_type` field ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) * deprecating `daos_version` field ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) ### Documentation * updated `directory_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is now immutable ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) * updated documentation for field `daos_version` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is deprecated. ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) * Updated field `file_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflected that message is now immutable ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1))
google-cloud-parametermanager: 0.1.1 ## [0.1.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-parametermanager-v0.1.0...google-cloud-parametermanager-v0.1.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-phishing-protection: 1.14.0 ## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-phishing-protection-v1.13.0...google-cloud-phishing-protection-v1.14.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-policy-troubleshooter: 1.13.1 ## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policy-troubleshooter-v1.13.0...google-cloud-policy-troubleshooter-v1.13.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-policysimulator: 0.1.12 ## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policysimulator-v0.1.11...google-cloud-policysimulator-v0.1.12) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-policytroubleshooter-iam: 0.1.11 ## [0.1.11](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policytroubleshooter-iam-v0.1.10...google-cloud-policytroubleshooter-iam-v0.1.11) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-private-ca: 1.14.1 ## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-ca-v1.14.0...google-cloud-private-ca-v1.14.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-private-catalog: 0.9.16 ## [0.9.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-catalog-v0.9.15...google-cloud-private-catalog-v0.9.16) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-privilegedaccessmanager: 0.1.6 ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-cloud-privilegedaccessmanager-v0.1.5...google-cloud-privilegedaccessmanager-v0.1.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-public-ca: 0.3.16 ## [0.3.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-public-ca-v0.3.15...google-cloud-public-ca-v0.3.16) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-quotas: 0.1.16 ## [0.1.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-quotas-v0.1.15...google-cloud-quotas-v0.1.16) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-rapidmigrationassessment: 0.1.13 ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-rapidmigrationassessment-v0.1.12...google-cloud-rapidmigrationassessment-v0.1.13) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-recaptcha-enterprise: 1.27.0 ## [1.27.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recaptcha-enterprise-v1.26.1...google-cloud-recaptcha-enterprise-v1.27.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-recommendations-ai: 0.10.16 ## [0.10.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommendations-ai-v0.10.15...google-cloud-recommendations-ai-v0.10.16) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-recommender: 2.18.0 ## [2.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommender-v2.17.0...google-cloud-recommender-v2.18.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-redis: 2.18.0 ## [2.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-v2.17.0...google-cloud-redis-v2.18.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-redis-cluster: 0.1.14 ## [0.1.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-cluster-v0.1.13...google-cloud-redis-cluster-v0.1.14) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-resource-manager: 1.14.1 ## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-manager-v1.14.0...google-cloud-resource-manager-v1.14.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-resource-settings: 1.12.0 ## [1.12.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-settings-v1.11.0...google-cloud-resource-settings-v1.12.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-retail: 1.25.0 ## [1.25.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-retail-v1.24.0...google-cloud-retail-v1.25.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-run: 0.10.16 ## [0.10.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-run-v0.10.15...google-cloud-run-v0.10.16) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-scheduler: 2.16.0 ## [2.16.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-scheduler-v2.15.1...google-cloud-scheduler-v2.16.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) * Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59))
google-cloud-secret-manager: 2.23.1 ## [2.23.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-secret-manager-v2.23.0...google-cloud-secret-manager-v2.23.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-securesourcemanager: 0.1.14 ## [0.1.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securesourcemanager-v0.1.13...google-cloud-securesourcemanager-v0.1.14) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-securitycenter: 1.38.0 ## [1.38.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycenter-v1.37.0...google-cloud-securitycenter-v1.38.0) (2025-02-18) ### Features * added data access event fields to finding proto ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b)) * added more information about DDoS attack in cloud armor proto ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b)) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) ### Documentation * Clarified comments for tag_values field in resource_value_config to make it clear that field represents tag value ids, not tag values ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b))
google-cloud-securitycentermanagement: 0.1.20 ## [0.1.20](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycentermanagement-v0.1.19...google-cloud-securitycentermanagement-v0.1.20) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-service-directory: 1.14.1 ## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-directory-v1.14.0...google-cloud-service-directory-v1.14.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-service-management: 1.13.1 ## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-management-v1.13.0...google-cloud-service-management-v1.13.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-tasks: 2.19.1 ## [2.19.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-tasks-v2.19.0...google-cloud-tasks-v2.19.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-translate: 3.20.1 ## [3.20.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-translate-v3.20.0...google-cloud-translate-v3.20.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-visionai: 0.1.8 ## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-cloud-visionai-v0.1.7...google-cloud-visionai-v0.1.8) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31))
google-cloud-vm-migration: 1.11.1 ## [1.11.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vm-migration-v1.11.0...google-cloud-vm-migration-v1.11.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8))
google-cloud-vmwareengine: 1.8.1 ## [1.8.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vmwareengine-v1.8.0...google-cloud-vmwareengine-v1.8.1) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8))
google-cloud-workstations: 0.5.13 ## [0.5.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-workstations-v0.5.12...google-cloud-workstations-v0.5.13) (2025-02-18) ### Bug Fixes * **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8))
google-maps-mapsplatformdatasets: 0.4.6 ## [0.4.6](https://github.com/googleapis/google-cloud-python/compare/google-maps-mapsplatformdatasets-v0.4.5...google-maps-mapsplatformdatasets-v0.4.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-maps-routeoptimization: 0.1.8 ## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-maps-routeoptimization-v0.1.7...google-maps-routeoptimization-v0.1.8) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-maps-routing: 0.6.14 ## [0.6.14](https://github.com/googleapis/google-cloud-python/compare/google-maps-routing-v0.6.13...google-maps-routing-v0.6.14) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-maps-solar: 0.1.6 ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-maps-solar-v0.1.5...google-maps-solar-v0.1.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-css: 0.1.13 ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-css-v0.1.12...google-shopping-css-v0.1.13) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-accounts: 0.2.4 ## [0.2.4](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-accounts-v0.2.3...google-shopping-merchant-accounts-v0.2.4) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-conversions: 0.1.7 ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-conversions-v0.1.6...google-shopping-merchant-conversions-v0.1.7) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-datasources: 0.1.8 ## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-datasources-v0.1.7...google-shopping-merchant-datasources-v0.1.8) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-inventories: 0.1.13 ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-inventories-v0.1.12...google-shopping-merchant-inventories-v0.1.13) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-lfp: 0.1.7 ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-lfp-v0.1.6...google-shopping-merchant-lfp-v0.1.7) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-notifications: 0.1.6 ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-notifications-v0.1.5...google-shopping-merchant-notifications-v0.1.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-products: 0.2.1 ## [0.2.1](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-products-v0.2.0...google-shopping-merchant-products-v0.2.1) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-promotions: 0.1.6 ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-promotions-v0.1.5...google-shopping-merchant-promotions-v0.1.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-quota: 0.1.6 ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-quota-v0.1.5...google-shopping-merchant-quota-v0.1.6) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-reports: 0.1.13 ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-reports-v0.1.12...google-shopping-merchant-reports-v0.1.13) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-merchant-reviews: 0.1.1 ## [0.1.1](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-reviews-v0.1.0...google-shopping-merchant-reviews-v0.1.1) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
google-shopping-type: 0.1.10 ## [0.1.10](https://github.com/googleapis/google-cloud-python/compare/google-shopping-type-v0.1.9...google-shopping-type-v0.1.10) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
googleapis-common-protos: 1.68.0 ## [1.68.0](https://github.com/googleapis/google-cloud-python/compare/googleapis-common-protos-v1.67.0...googleapis-common-protos-v1.68.0) (2025-02-18) ### Features * A new field `unversioned_package_disabled` is added to message `.google.api.PythonSettings` ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab)) * Add field `experimental_features` to message `PythonSettings` ([#249](https://github.com/googleapis/google-cloud-python/issues/249)) ([ba8d36e](https://github.com/googleapis/google-cloud-python/commit/ba8d36e4a288c57be235c8597e11208359b072b5)) * add FieldInfo.referenced_types for generics ([#247](https://github.com/googleapis/google-cloud-python/issues/247)) ([c91900a](https://github.com/googleapis/google-cloud-python/commit/c91900ab232e542905cd4f3cf282677bc6bcaab3)) * add support for field generate_omitted_as_internal in selective gapic generation ([#13482](https://github.com/googleapis/google-cloud-python/issues/13482)) ([993ff4d](https://github.com/googleapis/google-cloud-python/commit/993ff4db8ae64ab1ca1b45de2caf118effb003af)) ### Documentation * A comment for field `content` in message `.google.api.Page` is changed ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab)) * A comment for message `RoutingRule` is changed ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab))
grafeas: 1.14.0 ## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/grafeas-v1.13.0...grafeas-v1.14.0) (2025-02-18) ### Features * Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) * Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- .release-please-manifest.json | 198 +++++++++--------- packages/google-cloud-alloydb/CHANGELOG.md | 7 + .../google/cloud/alloydb/gapic_version.py | 2 +- .../google/cloud/alloydb_v1/gapic_version.py | 2 +- .../cloud/alloydb_v1alpha/gapic_version.py | 2 +- .../cloud/alloydb_v1beta/gapic_version.py | 2 +- ...ppet_metadata_google.cloud.alloydb.v1.json | 2 +- ...metadata_google.cloud.alloydb.v1alpha.json | 2 +- ..._metadata_google.cloud.alloydb.v1beta.json | 2 +- .../google-cloud-apigee-registry/CHANGELOG.md | 7 + .../cloud/apigee_registry/gapic_version.py | 2 +- .../cloud/apigee_registry_v1/gapic_version.py | 2 +- ...tadata_google.cloud.apigeeregistry.v1.json | 2 +- packages/google-cloud-apphub/CHANGELOG.md | 7 + .../google/cloud/apphub/gapic_version.py | 2 +- .../google/cloud/apphub_v1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.apphub.v1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/artifactregistry/gapic_version.py | 2 +- .../artifactregistry_v1/gapic_version.py | 2 +- .../artifactregistry_v1beta2/gapic_version.py | 2 +- ...a_google.devtools.artifactregistry.v1.json | 2 +- ...gle.devtools.artifactregistry.v1beta2.json | 2 +- packages/google-cloud-asset/CHANGELOG.md | 7 + .../google/cloud/asset/gapic_version.py | 2 +- .../google/cloud/asset_v1/gapic_version.py | 2 +- .../cloud/asset_v1p1beta1/gapic_version.py | 2 +- .../cloud/asset_v1p2beta1/gapic_version.py | 2 +- .../cloud/asset_v1p4beta1/gapic_version.py | 2 +- .../cloud/asset_v1p5beta1/gapic_version.py | 2 +- ...nippet_metadata_google.cloud.asset.v1.json | 2 +- ...metadata_google.cloud.asset.v1p1beta1.json | 2 +- ...metadata_google.cloud.asset.v1p2beta1.json | 2 +- ...metadata_google.cloud.asset.v1p5beta1.json | 2 +- packages/google-cloud-automl/CHANGELOG.md | 7 + .../google/cloud/automl/gapic_version.py | 2 +- .../google/cloud/automl_v1/gapic_version.py | 2 +- .../cloud/automl_v1beta1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.automl.v1.json | 2 +- ..._metadata_google.cloud.automl.v1beta1.json | 2 +- packages/google-cloud-backupdr/CHANGELOG.md | 7 + .../google/cloud/backupdr/gapic_version.py | 2 +- .../google/cloud/backupdr_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.backupdr.v1.json | 2 +- .../CHANGELOG.md | 7 + .../bare_metal_solution/gapic_version.py | 2 +- .../bare_metal_solution_v2/gapic_version.py | 2 +- ...ata_google.cloud.baremetalsolution.v2.json | 2 +- .../CHANGELOG.md | 7 + .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...le.cloud.beyondcorp.appconnections.v1.json | 2 +- .../CHANGELOG.md | 7 + .../beyondcorp_appconnectors/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...gle.cloud.beyondcorp.appconnectors.v1.json | 2 +- .../CHANGELOG.md | 7 + .../beyondcorp_appgateways/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...oogle.cloud.beyondcorp.appgateways.v1.json | 2 +- .../CHANGELOG.md | 7 + .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...beyondcorp.clientconnectorservices.v1.json | 2 +- .../CHANGELOG.md | 7 + .../gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...le.cloud.beyondcorp.clientgateways.v1.json | 2 +- .../CHANGELOG.md | 7 + .../bigquery_analyticshub/gapic_version.py | 2 +- .../bigquery_analyticshub_v1/gapic_version.py | 2 +- ...google.cloud.bigquery.analyticshub.v1.json | 2 +- .../CHANGELOG.md | 7 + .../bigquery_connection/gapic_version.py | 2 +- .../bigquery_connection_v1/gapic_version.py | 2 +- ...a_google.cloud.bigquery.connection.v1.json | 2 +- .../CHANGELOG.md | 7 + .../bigquery_data_exchange/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...e.cloud.bigquery.dataexchange.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../bigquery_datapolicies/gapic_version.py | 2 +- .../bigquery_datapolicies_v1/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...google.cloud.bigquery.datapolicies.v1.json | 2 +- ...e.cloud.bigquery.datapolicies.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/bigquery_logging/gapic_version.py | 2 +- .../bigquery_logging_v1/gapic_version.py | 2 +- packages/google-cloud-billing/CHANGELOG.md | 7 + .../google/cloud/billing/gapic_version.py | 2 +- .../google/cloud/billing_v1/gapic_version.py | 2 +- ...ppet_metadata_google.cloud.billing.v1.json | 2 +- packages/google-cloud-build/CHANGELOG.md | 18 ++ .../devtools/cloudbuild/gapic_version.py | 2 +- .../devtools/cloudbuild_v1/gapic_version.py | 2 +- .../devtools/cloudbuild_v2/gapic_version.py | 2 +- ...etadata_google.devtools.cloudbuild.v1.json | 2 +- ...etadata_google.devtools.cloudbuild.v2.json | 2 +- packages/google-cloud-config/CHANGELOG.md | 7 + .../google/cloud/config/gapic_version.py | 2 +- .../google/cloud/config_v1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.config.v1.json | 2 +- .../CHANGELOG.md | 7 + .../contact_center_insights/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...google.cloud.contactcenterinsights.v1.json | 2 +- .../CHANGELOG.md | 7 + .../containeranalysis/gapic_version.py | 2 +- .../containeranalysis_v1/gapic_version.py | 2 +- ..._google.devtools.containeranalysis.v1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/contentwarehouse/gapic_version.py | 2 +- .../contentwarehouse_v1/gapic_version.py | 2 +- ...data_google.cloud.contentwarehouse.v1.json | 2 +- .../google-cloud-data-fusion/CHANGELOG.md | 7 + .../google/cloud/data_fusion/gapic_version.py | 2 +- .../cloud/data_fusion_v1/gapic_version.py | 2 +- ...t_metadata_google.cloud.datafusion.v1.json | 2 +- .../google-cloud-datacatalog/CHANGELOG.md | 7 + .../google/cloud/datacatalog/gapic_version.py | 2 +- .../cloud/datacatalog_v1/gapic_version.py | 2 +- .../datacatalog_v1beta1/gapic_version.py | 2 +- ..._metadata_google.cloud.datacatalog.v1.json | 2 +- ...data_google.cloud.datacatalog.v1beta1.json | 2 +- packages/google-cloud-dataform/CHANGELOG.md | 7 + .../google/cloud/dataform/gapic_version.py | 2 +- .../cloud/dataform_v1beta1/gapic_version.py | 2 +- ...etadata_google.cloud.dataform.v1beta1.json | 2 +- packages/google-cloud-dataplex/CHANGELOG.md | 7 + .../google/cloud/dataplex/gapic_version.py | 2 +- .../google/cloud/dataplex_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.dataplex.v1.json | 2 +- .../CHANGELOG.md | 7 + .../google/cloud/metastore/gapic_version.py | 2 +- .../cloud/metastore_v1/gapic_version.py | 2 +- .../cloud/metastore_v1alpha/gapic_version.py | 2 +- .../cloud/metastore_v1beta/gapic_version.py | 2 +- ...et_metadata_google.cloud.metastore.v1.json | 2 +- ...tadata_google.cloud.metastore.v1alpha.json | 2 +- ...etadata_google.cloud.metastore.v1beta.json | 2 +- packages/google-cloud-dataproc/CHANGELOG.md | 7 + .../google/cloud/dataproc/gapic_version.py | 2 +- .../google/cloud/dataproc_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.dataproc.v1.json | 2 +- packages/google-cloud-datastream/CHANGELOG.md | 7 + .../google/cloud/datastream/gapic_version.py | 2 +- .../cloud/datastream_v1/gapic_version.py | 2 +- .../datastream_v1alpha1/gapic_version.py | 2 +- ...t_metadata_google.cloud.datastream.v1.json | 2 +- ...data_google.cloud.datastream.v1alpha1.json | 2 +- packages/google-cloud-deploy/CHANGELOG.md | 7 + .../google/cloud/deploy/gapic_version.py | 2 +- .../google/cloud/deploy_v1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.deploy.v1.json | 2 +- packages/google-cloud-dms/CHANGELOG.md | 7 + .../google/cloud/clouddms/gapic_version.py | 2 +- .../google/cloud/clouddms_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.clouddms.v1.json | 2 +- packages/google-cloud-eventarc/CHANGELOG.md | 7 + .../google/cloud/eventarc/gapic_version.py | 2 +- .../google/cloud/eventarc_v1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.eventarc.v1.json | 2 +- packages/google-cloud-functions/CHANGELOG.md | 7 + .../google/cloud/functions/gapic_version.py | 2 +- .../cloud/functions_v1/gapic_version.py | 2 +- .../cloud/functions_v2/gapic_version.py | 2 +- ...et_metadata_google.cloud.functions.v1.json | 2 +- ...et_metadata_google.cloud.functions.v2.json | 2 +- packages/google-cloud-gke-backup/CHANGELOG.md | 7 + .../google/cloud/gke_backup/gapic_version.py | 2 +- .../cloud/gke_backup_v1/gapic_version.py | 2 +- ...et_metadata_google.cloud.gkebackup.v1.json | 2 +- packages/google-cloud-gke-hub/CHANGELOG.md | 7 + .../google/cloud/gkehub/gapic_version.py | 2 +- .../configmanagement_v1/gapic_version.py | 2 +- .../google/cloud/gkehub_v1/gapic_version.py | 2 +- .../multiclusteringress_v1/gapic_version.py | 2 +- .../cloud/gkehub_v1beta1/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.gkehub.v1.json | 2 +- ..._metadata_google.cloud.gkehub.v1beta1.json | 2 +- .../google-cloud-iam-logging/CHANGELOG.md | 7 + .../google/cloud/iam_logging/gapic_version.py | 2 +- .../cloud/iam_logging_v1/gapic_version.py | 2 +- packages/google-cloud-iam/CHANGELOG.md | 7 + .../google/cloud/iam/gapic_version.py | 2 +- .../google/cloud/iam_admin/gapic_version.py | 2 +- .../cloud/iam_admin_v1/gapic_version.py | 2 +- .../cloud/iam_credentials/gapic_version.py | 2 +- .../cloud/iam_credentials_v1/gapic_version.py | 2 +- .../google/cloud/iam_v2/gapic_version.py | 2 +- .../google/cloud/iam_v2beta/gapic_version.py | 2 +- .../snippet_metadata_google.iam.admin.v1.json | 2 +- ...et_metadata_google.iam.credentials.v1.json | 2 +- .../snippet_metadata_google.iam.v2.json | 2 +- .../snippet_metadata_google.iam.v2beta.json | 2 +- packages/google-cloud-iap/CHANGELOG.md | 7 + .../google/cloud/iap/gapic_version.py | 2 +- .../google/cloud/iap_v1/gapic_version.py | 2 +- .../snippet_metadata_google.cloud.iap.v1.json | 2 +- packages/google-cloud-kms/CHANGELOG.md | 7 + .../google/cloud/kms/gapic_version.py | 2 +- .../google/cloud/kms_v1/gapic_version.py | 2 +- .../snippet_metadata_google.cloud.kms.v1.json | 2 +- .../CHANGELOG.md | 7 + .../networkconnectivity/gapic_version.py | 2 +- .../networkconnectivity_v1/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...a_google.cloud.networkconnectivity.v1.json | 2 +- ...le.cloud.networkconnectivity.v1alpha1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/network_management/gapic_version.py | 2 +- .../network_management_v1/gapic_version.py | 2 +- ...ata_google.cloud.networkmanagement.v1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/network_security/gapic_version.py | 2 +- .../network_security_v1/gapic_version.py | 2 +- .../network_security_v1beta1/gapic_version.py | 2 +- ...adata_google.cloud.networksecurity.v1.json | 2 +- ..._google.cloud.networksecurity.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/network_services/gapic_version.py | 2 +- .../network_services_v1/gapic_version.py | 2 +- ...adata_google.cloud.networkservices.v1.json | 2 +- packages/google-cloud-notebooks/CHANGELOG.md | 7 + .../google/cloud/notebooks/gapic_version.py | 2 +- .../cloud/notebooks_v1/gapic_version.py | 2 +- .../cloud/notebooks_v1beta1/gapic_version.py | 2 +- .../cloud/notebooks_v2/gapic_version.py | 2 +- ...et_metadata_google.cloud.notebooks.v1.json | 2 +- ...tadata_google.cloud.notebooks.v1beta1.json | 2 +- ...et_metadata_google.cloud.notebooks.v2.json | 2 +- .../google-cloud-parallelstore/CHANGELOG.md | 15 ++ .../cloud/parallelstore/gapic_version.py | 2 +- .../cloud/parallelstore_v1/gapic_version.py | 2 +- .../parallelstore_v1beta/gapic_version.py | 2 +- ...etadata_google.cloud.parallelstore.v1.json | 2 +- ...ata_google.cloud.parallelstore.v1beta.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/parametermanager/gapic_version.py | 2 +- .../parametermanager_v1/gapic_version.py | 2 +- ...data_google.cloud.parametermanager.v1.json | 2 +- .../CHANGELOG.md | 8 + .../cloud/phishingprotection/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...ogle.cloud.phishingprotection.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../policytroubleshooter/gapic_version.py | 2 +- .../policytroubleshooter_v1/gapic_version.py | 2 +- ..._google.cloud.policytroubleshooter.v1.json | 2 +- .../google-cloud-policysimulator/CHANGELOG.md | 7 + .../cloud/policysimulator/gapic_version.py | 2 +- .../cloud/policysimulator_v1/gapic_version.py | 2 +- ...adata_google.cloud.policysimulator.v1.json | 2 +- .../CHANGELOG.md | 7 + .../policytroubleshooter_iam/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...gle.cloud.policytroubleshooter.iam.v3.json | 2 +- packages/google-cloud-private-ca/CHANGELOG.md | 7 + .../cloud/security/privateca/gapic_version.py | 2 +- .../security/privateca_v1/gapic_version.py | 2 +- .../privateca_v1beta1/gapic_version.py | 2 +- ...ta_google.cloud.security.privateca.v1.json | 2 +- ...ogle.cloud.security.privateca.v1beta1.json | 2 +- .../google-cloud-private-catalog/CHANGELOG.md | 8 + .../cloud/privatecatalog/gapic_version.py | 2 +- .../privatecatalog_v1beta1/gapic_version.py | 2 +- ...a_google.cloud.privatecatalog.v1beta1.json | 2 +- .../CHANGELOG.md | 8 + .../privilegedaccessmanager/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...ogle.cloud.privilegedaccessmanager.v1.json | 2 +- packages/google-cloud-public-ca/CHANGELOG.md | 8 + .../cloud/security/publicca/gapic_version.py | 2 +- .../security/publicca_v1/gapic_version.py | 2 +- .../publicca_v1beta1/gapic_version.py | 2 +- ...ata_google.cloud.security.publicca.v1.json | 2 +- ...oogle.cloud.security.publicca.v1beta1.json | 2 +- packages/google-cloud-quotas/CHANGELOG.md | 8 + .../google/cloud/cloudquotas/gapic_version.py | 2 +- .../cloud/cloudquotas_v1/gapic_version.py | 2 +- .../cloud/cloudquotas_v1beta/gapic_version.py | 2 +- ...et_metadata_google.api.cloudquotas.v1.json | 2 +- ...etadata_google.api.cloudquotas.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../rapidmigrationassessment/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...gle.cloud.rapidmigrationassessment.v1.json | 2 +- .../CHANGELOG.md | 8 + .../recaptchaenterprise/gapic_version.py | 2 +- .../recaptchaenterprise_v1/gapic_version.py | 2 +- ...a_google.cloud.recaptchaenterprise.v1.json | 2 +- .../CHANGELOG.md | 8 + .../recommendationengine/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...le.cloud.recommendationengine.v1beta1.json | 2 +- .../google-cloud-recommender/CHANGELOG.md | 8 + .../google/cloud/recommender/gapic_version.py | 2 +- .../cloud/recommender_v1/gapic_version.py | 2 +- .../recommender_v1beta1/gapic_version.py | 2 +- ..._metadata_google.cloud.recommender.v1.json | 2 +- ...data_google.cloud.recommender.v1beta1.json | 2 +- .../google-cloud-redis-cluster/CHANGELOG.md | 8 + .../cloud/redis_cluster/gapic_version.py | 2 +- .../cloud/redis_cluster_v1/gapic_version.py | 2 +- .../redis_cluster_v1beta1/gapic_version.py | 2 +- ...etadata_google.cloud.redis.cluster.v1.json | 2 +- ...ta_google.cloud.redis.cluster.v1beta1.json | 2 +- packages/google-cloud-redis/CHANGELOG.md | 8 + .../google/cloud/redis/gapic_version.py | 2 +- .../google/cloud/redis_v1/gapic_version.py | 2 +- .../cloud/redis_v1beta1/gapic_version.py | 2 +- ...nippet_metadata_google.cloud.redis.v1.json | 2 +- ...t_metadata_google.cloud.redis.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/resourcemanager/gapic_version.py | 2 +- .../cloud/resourcemanager_v3/gapic_version.py | 2 +- ...adata_google.cloud.resourcemanager.v3.json | 2 +- .../CHANGELOG.md | 8 + .../cloud/resourcesettings/gapic_version.py | 2 +- .../resourcesettings_v1/gapic_version.py | 2 +- ...data_google.cloud.resourcesettings.v1.json | 2 +- packages/google-cloud-retail/CHANGELOG.md | 8 + .../google/cloud/retail/gapic_version.py | 2 +- .../google/cloud/retail_v2/gapic_version.py | 2 +- .../cloud/retail_v2alpha/gapic_version.py | 2 +- .../cloud/retail_v2beta/gapic_version.py | 2 +- ...ippet_metadata_google.cloud.retail.v2.json | 2 +- ..._metadata_google.cloud.retail.v2alpha.json | 2 +- ...t_metadata_google.cloud.retail.v2beta.json | 2 +- packages/google-cloud-run/CHANGELOG.md | 7 + .../google/cloud/run/gapic_version.py | 2 +- .../google/cloud/run_v2/gapic_version.py | 2 +- .../snippet_metadata_google.cloud.run.v2.json | 2 +- packages/google-cloud-scheduler/CHANGELOG.md | 8 + .../google/cloud/scheduler/gapic_version.py | 2 +- .../cloud/scheduler_v1/gapic_version.py | 2 +- .../cloud/scheduler_v1beta1/gapic_version.py | 2 +- ...et_metadata_google.cloud.scheduler.v1.json | 2 +- ...tadata_google.cloud.scheduler.v1beta1.json | 2 +- .../google-cloud-secret-manager/CHANGELOG.md | 7 + .../cloud/secretmanager/gapic_version.py | 2 +- .../cloud/secretmanager_v1/gapic_version.py | 2 +- .../secretmanager_v1beta1/gapic_version.py | 2 +- .../secretmanager_v1beta2/gapic_version.py | 2 +- ...etadata_google.cloud.secretmanager.v1.json | 2 +- ...ta_google.cloud.secretmanager.v1beta2.json | 2 +- ...metadata_google.cloud.secrets.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../securesourcemanager/gapic_version.py | 2 +- .../securesourcemanager_v1/gapic_version.py | 2 +- ...a_google.cloud.securesourcemanager.v1.json | 2 +- .../google-cloud-securitycenter/CHANGELOG.md | 18 ++ .../cloud/securitycenter/gapic_version.py | 2 +- .../cloud/securitycenter_v1/gapic_version.py | 2 +- .../securitycenter_v1beta1/gapic_version.py | 2 +- .../securitycenter_v1p1beta1/gapic_version.py | 2 +- .../cloud/securitycenter_v2/gapic_version.py | 2 +- ...tadata_google.cloud.securitycenter.v1.json | 2 +- ...a_google.cloud.securitycenter.v1beta1.json | 2 +- ...google.cloud.securitycenter.v1p1beta1.json | 2 +- ...tadata_google.cloud.securitycenter.v2.json | 2 +- .../CHANGELOG.md | 7 + .../securitycentermanagement/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...gle.cloud.securitycentermanagement.v1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/servicedirectory/gapic_version.py | 2 +- .../servicedirectory_v1/gapic_version.py | 2 +- .../servicedirectory_v1beta1/gapic_version.py | 2 +- ...data_google.cloud.servicedirectory.v1.json | 2 +- ...google.cloud.servicedirectory.v1beta1.json | 2 +- .../CHANGELOG.md | 7 + .../cloud/servicemanagement/gapic_version.py | 2 +- .../servicemanagement_v1/gapic_version.py | 2 +- ...adata_google.api.servicemanagement.v1.json | 2 +- packages/google-cloud-tasks/CHANGELOG.md | 7 + .../google/cloud/tasks/gapic_version.py | 2 +- .../google/cloud/tasks_v2/gapic_version.py | 2 +- .../cloud/tasks_v2beta2/gapic_version.py | 2 +- .../cloud/tasks_v2beta3/gapic_version.py | 2 +- ...nippet_metadata_google.cloud.tasks.v2.json | 2 +- ...t_metadata_google.cloud.tasks.v2beta2.json | 2 +- ...t_metadata_google.cloud.tasks.v2beta3.json | 2 +- packages/google-cloud-translate/CHANGELOG.md | 7 + .../google/cloud/translate/gapic_version.py | 2 +- .../cloud/translate_v3/gapic_version.py | 2 +- .../cloud/translate_v3beta1/gapic_version.py | 2 +- ..._metadata_google.cloud.translation.v3.json | 2 +- ...data_google.cloud.translation.v3beta1.json | 2 +- packages/google-cloud-visionai/CHANGELOG.md | 7 + .../google/cloud/visionai/gapic_version.py | 2 +- .../google/cloud/visionai_v1/gapic_version.py | 2 +- .../cloud/visionai_v1alpha1/gapic_version.py | 2 +- ...pet_metadata_google.cloud.visionai.v1.json | 2 +- ...tadata_google.cloud.visionai.v1alpha1.json | 2 +- .../google-cloud-vm-migration/CHANGELOG.md | 7 + .../google/cloud/vmmigration/gapic_version.py | 2 +- .../cloud/vmmigration_v1/gapic_version.py | 2 +- ..._metadata_google.cloud.vmmigration.v1.json | 2 +- .../google-cloud-vmwareengine/CHANGELOG.md | 7 + .../cloud/vmwareengine/gapic_version.py | 2 +- .../cloud/vmwareengine_v1/gapic_version.py | 2 +- ...metadata_google.cloud.vmwareengine.v1.json | 2 +- .../google-cloud-workstations/CHANGELOG.md | 7 + .../cloud/workstations/gapic_version.py | 2 +- .../cloud/workstations_v1/gapic_version.py | 2 +- .../workstations_v1beta/gapic_version.py | 2 +- ...metadata_google.cloud.workstations.v1.json | 2 +- ...data_google.cloud.workstations.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../mapsplatformdatasets/gapic_version.py | 2 +- .../mapsplatformdatasets_v1/gapic_version.py | 2 +- ...a_google.maps.mapsplatformdatasets.v1.json | 2 +- .../CHANGELOG.md | 8 + .../maps/routeoptimization/gapic_version.py | 2 +- .../routeoptimization_v1/gapic_version.py | 2 +- ...data_google.maps.routeoptimization.v1.json | 2 +- packages/google-maps-routing/CHANGELOG.md | 8 + .../google/maps/routing/gapic_version.py | 2 +- .../google/maps/routing_v2/gapic_version.py | 2 +- ...ippet_metadata_google.maps.routing.v2.json | 2 +- packages/google-maps-solar/CHANGELOG.md | 8 + .../google/maps/solar/gapic_version.py | 2 +- .../google/maps/solar_v1/gapic_version.py | 2 +- ...snippet_metadata_google.maps.solar.v1.json | 2 +- packages/google-shopping-css/CHANGELOG.md | 8 + .../google/shopping/css/gapic_version.py | 2 +- .../google/shopping/css_v1/gapic_version.py | 2 +- ...ippet_metadata_google.shopping.css.v1.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_accounts/gapic_version.py | 2 +- .../merchant_accounts_v1beta/gapic_version.py | 2 +- ...gle.shopping.merchant.accounts.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_conversions/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ....shopping.merchant.conversions.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_datasources/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ....shopping.merchant.datasources.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_inventories/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ....shopping.merchant.inventories.v1beta.json | 2 +- .../google-shopping-merchant-lfp/CHANGELOG.md | 8 + .../shopping/merchant_lfp/gapic_version.py | 2 +- .../merchant_lfp_v1beta/gapic_version.py | 2 +- ...a_google.shopping.merchant.lfp.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_notifications/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...hopping.merchant.notifications.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_products/gapic_version.py | 2 +- .../merchant_products_v1beta/gapic_version.py | 2 +- ...gle.shopping.merchant.products.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_promotions/gapic_version.py | 2 +- .../gapic_version.py | 2 +- ...e.shopping.merchant.promotions.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../shopping/merchant_quota/gapic_version.py | 2 +- .../merchant_quota_v1beta/gapic_version.py | 2 +- ...google.shopping.merchant.quota.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_reports/gapic_version.py | 2 +- .../merchant_reports_v1beta/gapic_version.py | 2 +- ...ogle.shopping.merchant.reports.v1beta.json | 2 +- .../CHANGELOG.md | 8 + .../merchant_reviews/gapic_version.py | 2 +- .../merchant_reviews_v1beta/gapic_version.py | 2 +- ...ogle.shopping.merchant.reviews.v1beta.json | 2 +- packages/google-shopping-type/CHANGELOG.md | 8 + .../google/shopping/type/gapic_version.py | 2 +- .../googleapis-common-protos/CHANGELOG.md | 16 ++ packages/googleapis-common-protos/setup.py | 2 +- packages/grafeas/CHANGELOG.md | 8 + .../grafeas/grafeas/grafeas/gapic_version.py | 2 +- .../grafeas/grafeas_v1/gapic_version.py | 2 +- .../snippet_metadata_grafeas.v1.json | 2 +- 482 files changed, 1245 insertions(+), 481 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fa9947f7ddc9..04d36ae7c078 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -13,42 +13,42 @@ "packages/google-cloud-access-approval": "1.16.0", "packages/google-cloud-access-context-manager": "0.2.1", "packages/google-cloud-advisorynotifications": "0.3.14", - "packages/google-cloud-alloydb": "0.4.2", + "packages/google-cloud-alloydb": "0.4.3", "packages/google-cloud-alloydb-connectors": "0.1.8", "packages/google-cloud-api-gateway": "1.12.0", "packages/google-cloud-api-keys": "0.5.15", "packages/google-cloud-apigee-connect": "1.12.0", - "packages/google-cloud-apigee-registry": "0.6.15", + "packages/google-cloud-apigee-registry": "0.6.16", "packages/google-cloud-apihub": "0.2.4", "packages/google-cloud-appengine-admin": "1.14.0", "packages/google-cloud-appengine-logging": "1.6.0", - "packages/google-cloud-apphub": "0.1.6", - "packages/google-cloud-artifact-registry": "1.15.0", - "packages/google-cloud-asset": "3.29.0", + "packages/google-cloud-apphub": "0.1.7", + "packages/google-cloud-artifact-registry": "1.15.1", + "packages/google-cloud-asset": "3.29.1", "packages/google-cloud-assured-workloads": "1.15.0", "packages/google-cloud-audit-log": "0.3.0", - "packages/google-cloud-automl": "2.16.0", - "packages/google-cloud-backupdr": "0.2.1", - "packages/google-cloud-bare-metal-solution": "1.10.0", + "packages/google-cloud-automl": "2.16.1", + "packages/google-cloud-backupdr": "0.2.2", + "packages/google-cloud-bare-metal-solution": "1.10.1", "packages/google-cloud-batch": "0.17.34", - "packages/google-cloud-beyondcorp-appconnections": "0.4.15", - "packages/google-cloud-beyondcorp-appconnectors": "0.4.15", - "packages/google-cloud-beyondcorp-appgateways": "0.4.15", - "packages/google-cloud-beyondcorp-clientconnectorservices": "0.4.15", - "packages/google-cloud-beyondcorp-clientgateways": "0.4.14", - "packages/google-cloud-bigquery-analyticshub": "0.4.15", + "packages/google-cloud-beyondcorp-appconnections": "0.4.16", + "packages/google-cloud-beyondcorp-appconnectors": "0.4.16", + "packages/google-cloud-beyondcorp-appgateways": "0.4.16", + "packages/google-cloud-beyondcorp-clientconnectorservices": "0.4.16", + "packages/google-cloud-beyondcorp-clientgateways": "0.4.15", + "packages/google-cloud-bigquery-analyticshub": "0.4.16", "packages/google-cloud-bigquery-biglake": "0.4.13", - "packages/google-cloud-bigquery-connection": "1.18.0", - "packages/google-cloud-bigquery-data-exchange": "0.5.17", - "packages/google-cloud-bigquery-datapolicies": "0.6.12", + "packages/google-cloud-bigquery-connection": "1.18.1", + "packages/google-cloud-bigquery-data-exchange": "0.5.18", + "packages/google-cloud-bigquery-datapolicies": "0.6.13", "packages/google-cloud-bigquery-datatransfer": "3.19.0", - "packages/google-cloud-bigquery-logging": "1.6.0", + "packages/google-cloud-bigquery-logging": "1.6.1", "packages/google-cloud-bigquery-migration": "0.11.13", "packages/google-cloud-bigquery-reservation": "1.16.0", - "packages/google-cloud-billing": "1.16.0", + "packages/google-cloud-billing": "1.16.1", "packages/google-cloud-billing-budgets": "1.17.0", "packages/google-cloud-binary-authorization": "1.13.0", - "packages/google-cloud-build": "3.30.0", + "packages/google-cloud-build": "3.31.0", "packages/google-cloud-certificate-manager": "1.10.0", "packages/google-cloud-channel": "1.22.0", "packages/google-cloud-cloudcontrolspartner": "0.2.5", @@ -56,50 +56,50 @@ "packages/google-cloud-common": "1.5.0", "packages/google-cloud-compute": "1.25.0", "packages/google-cloud-confidentialcomputing": "0.4.15", - "packages/google-cloud-config": "0.1.15", - "packages/google-cloud-contact-center-insights": "1.23.0", + "packages/google-cloud-config": "0.1.16", + "packages/google-cloud-contact-center-insights": "1.23.1", "packages/google-cloud-container": "2.56.0", - "packages/google-cloud-containeranalysis": "2.17.0", - "packages/google-cloud-contentwarehouse": "0.7.13", - "packages/google-cloud-data-fusion": "1.13.0", + "packages/google-cloud-containeranalysis": "2.17.1", + "packages/google-cloud-contentwarehouse": "0.7.14", + "packages/google-cloud-data-fusion": "1.13.1", "packages/google-cloud-data-qna": "0.10.15", - "packages/google-cloud-datacatalog": "3.25.0", + "packages/google-cloud-datacatalog": "3.25.1", "packages/google-cloud-datacatalog-lineage": "0.3.12", "packages/google-cloud-dataflow-client": "0.8.16", - "packages/google-cloud-dataform": "0.5.15", + "packages/google-cloud-dataform": "0.5.16", "packages/google-cloud-datalabeling": "1.13.0", - "packages/google-cloud-dataplex": "2.7.0", - "packages/google-cloud-dataproc": "5.17.0", - "packages/google-cloud-dataproc-metastore": "1.18.0", - "packages/google-cloud-datastream": "1.13.0", - "packages/google-cloud-deploy": "2.6.0", + "packages/google-cloud-dataplex": "2.7.1", + "packages/google-cloud-dataproc": "5.17.1", + "packages/google-cloud-dataproc-metastore": "1.18.1", + "packages/google-cloud-datastream": "1.13.1", + "packages/google-cloud-deploy": "2.6.1", "packages/google-cloud-developerconnect": "0.1.7", "packages/google-cloud-dialogflow": "2.39.0", "packages/google-cloud-dialogflow-cx": "1.39.0", "packages/google-cloud-discoveryengine": "0.13.6", "packages/google-cloud-dlp": "3.27.0", - "packages/google-cloud-dms": "1.12.0", + "packages/google-cloud-dms": "1.12.1", "packages/google-cloud-documentai": "3.2.0", "packages/google-cloud-domains": "1.10.0", "packages/google-cloud-edgecontainer": "0.5.16", "packages/google-cloud-edgenetwork": "0.1.15", "packages/google-cloud-enterpriseknowledgegraph": "0.3.15", "packages/google-cloud-essential-contacts": "1.10.0", - "packages/google-cloud-eventarc": "1.15.0", + "packages/google-cloud-eventarc": "1.15.1", "packages/google-cloud-eventarc-publishing": "0.6.16", "packages/google-cloud-filestore": "1.12.0", - "packages/google-cloud-functions": "1.20.0", + "packages/google-cloud-functions": "1.20.1", "packages/google-cloud-gdchardwaremanagement": "0.1.10", - "packages/google-cloud-gke-backup": "0.5.15", + "packages/google-cloud-gke-backup": "0.5.16", "packages/google-cloud-gke-connect-gateway": "0.10.2", - "packages/google-cloud-gke-hub": "1.17.0", + "packages/google-cloud-gke-hub": "1.17.1", "packages/google-cloud-gke-multicloud": "0.6.19", "packages/google-cloud-gsuiteaddons": "0.3.15", - "packages/google-cloud-iam": "2.18.0", - "packages/google-cloud-iam-logging": "1.4.0", - "packages/google-cloud-iap": "1.16.0", + "packages/google-cloud-iam": "2.18.1", + "packages/google-cloud-iam-logging": "1.4.1", + "packages/google-cloud-iap": "1.16.1", "packages/google-cloud-ids": "1.10.0", - "packages/google-cloud-kms": "3.3.0", + "packages/google-cloud-kms": "3.3.1", "packages/google-cloud-kms-inventory": "0.2.13", "packages/google-cloud-language": "2.17.0", "packages/google-cloud-life-sciences": "0.9.16", @@ -114,46 +114,46 @@ "packages/google-cloud-monitoring-dashboards": "2.18.0", "packages/google-cloud-monitoring-metrics-scopes": "1.9.0", "packages/google-cloud-netapp": "0.3.19", - "packages/google-cloud-network-connectivity": "2.7.0", - "packages/google-cloud-network-management": "1.25.0", - "packages/google-cloud-network-security": "0.9.15", - "packages/google-cloud-network-services": "0.5.18", - "packages/google-cloud-notebooks": "1.13.0", + "packages/google-cloud-network-connectivity": "2.7.1", + "packages/google-cloud-network-management": "1.25.1", + "packages/google-cloud-network-security": "0.9.16", + "packages/google-cloud-network-services": "0.5.19", + "packages/google-cloud-notebooks": "1.13.1", "packages/google-cloud-optimization": "1.11.0", "packages/google-cloud-oracledatabase": "0.1.5", "packages/google-cloud-orchestration-airflow": "1.17.0", "packages/google-cloud-org-policy": "1.13.0", "packages/google-cloud-os-config": "1.20.0", "packages/google-cloud-os-login": "2.17.0", - "packages/google-cloud-parallelstore": "0.2.10", - "packages/google-cloud-parametermanager": "0.1.0", - "packages/google-cloud-phishing-protection": "1.13.0", - "packages/google-cloud-policy-troubleshooter": "1.13.0", - "packages/google-cloud-policysimulator": "0.1.11", - "packages/google-cloud-policytroubleshooter-iam": "0.1.10", - "packages/google-cloud-private-ca": "1.14.0", - "packages/google-cloud-private-catalog": "0.9.15", - "packages/google-cloud-privilegedaccessmanager": "0.1.5", - "packages/google-cloud-public-ca": "0.3.15", - "packages/google-cloud-quotas": "0.1.15", - "packages/google-cloud-rapidmigrationassessment": "0.1.12", - "packages/google-cloud-recaptcha-enterprise": "1.26.1", - "packages/google-cloud-recommendations-ai": "0.10.15", - "packages/google-cloud-recommender": "2.17.0", - "packages/google-cloud-redis": "2.17.0", - "packages/google-cloud-redis-cluster": "0.1.13", - "packages/google-cloud-resource-manager": "1.14.0", - "packages/google-cloud-resource-settings": "1.11.0", - "packages/google-cloud-retail": "1.24.0", - "packages/google-cloud-run": "0.10.15", - "packages/google-cloud-scheduler": "2.15.1", - "packages/google-cloud-secret-manager": "2.23.0", - "packages/google-cloud-securesourcemanager": "0.1.13", - "packages/google-cloud-securitycenter": "1.37.0", - "packages/google-cloud-securitycentermanagement": "0.1.19", + "packages/google-cloud-parallelstore": "0.2.11", + "packages/google-cloud-parametermanager": "0.1.1", + "packages/google-cloud-phishing-protection": "1.14.0", + "packages/google-cloud-policy-troubleshooter": "1.13.1", + "packages/google-cloud-policysimulator": "0.1.12", + "packages/google-cloud-policytroubleshooter-iam": "0.1.11", + "packages/google-cloud-private-ca": "1.14.1", + "packages/google-cloud-private-catalog": "0.9.16", + "packages/google-cloud-privilegedaccessmanager": "0.1.6", + "packages/google-cloud-public-ca": "0.3.16", + "packages/google-cloud-quotas": "0.1.16", + "packages/google-cloud-rapidmigrationassessment": "0.1.13", + "packages/google-cloud-recaptcha-enterprise": "1.27.0", + "packages/google-cloud-recommendations-ai": "0.10.16", + "packages/google-cloud-recommender": "2.18.0", + "packages/google-cloud-redis": "2.18.0", + "packages/google-cloud-redis-cluster": "0.1.14", + "packages/google-cloud-resource-manager": "1.14.1", + "packages/google-cloud-resource-settings": "1.12.0", + "packages/google-cloud-retail": "1.25.0", + "packages/google-cloud-run": "0.10.16", + "packages/google-cloud-scheduler": "2.16.0", + "packages/google-cloud-secret-manager": "2.23.1", + "packages/google-cloud-securesourcemanager": "0.1.14", + "packages/google-cloud-securitycenter": "1.38.0", + "packages/google-cloud-securitycentermanagement": "0.1.20", "packages/google-cloud-service-control": "1.15.0", - "packages/google-cloud-service-directory": "1.14.0", - "packages/google-cloud-service-management": "1.13.0", + "packages/google-cloud-service-directory": "1.14.1", + "packages/google-cloud-service-management": "1.13.1", "packages/google-cloud-service-usage": "1.13.0", "packages/google-cloud-servicehealth": "0.1.11", "packages/google-cloud-shell": "1.12.0", @@ -164,49 +164,49 @@ "packages/google-cloud-storageinsights": "0.1.14", "packages/google-cloud-support": "0.1.13", "packages/google-cloud-talent": "2.17.0", - "packages/google-cloud-tasks": "2.19.0", + "packages/google-cloud-tasks": "2.19.1", "packages/google-cloud-telcoautomation": "0.2.9", "packages/google-cloud-texttospeech": "2.25.0", "packages/google-cloud-tpu": "1.23.0", "packages/google-cloud-trace": "1.16.0", - "packages/google-cloud-translate": "3.20.0", + "packages/google-cloud-translate": "3.20.1", "packages/google-cloud-video-live-stream": "1.11.0", "packages/google-cloud-video-stitcher": "0.7.16", "packages/google-cloud-video-transcoder": "1.15.0", "packages/google-cloud-videointelligence": "2.16.0", "packages/google-cloud-vision": "3.10.0", - "packages/google-cloud-visionai": "0.1.7", - "packages/google-cloud-vm-migration": "1.11.0", - "packages/google-cloud-vmwareengine": "1.8.0", + "packages/google-cloud-visionai": "0.1.8", + "packages/google-cloud-vm-migration": "1.11.1", + "packages/google-cloud-vmwareengine": "1.8.1", "packages/google-cloud-vpc-access": "1.13.0", "packages/google-cloud-webrisk": "1.17.0", "packages/google-cloud-websecurityscanner": "1.17.0", "packages/google-cloud-workflows": "1.17.0", - "packages/google-cloud-workstations": "0.5.12", + "packages/google-cloud-workstations": "0.5.13", "packages/google-geo-type": "0.3.11", "packages/google-maps-addressvalidation": "0.3.17", "packages/google-maps-areainsights": "0.1.4", "packages/google-maps-fleetengine": "0.2.6", "packages/google-maps-fleetengine-delivery": "0.2.8", - "packages/google-maps-mapsplatformdatasets": "0.4.5", + "packages/google-maps-mapsplatformdatasets": "0.4.6", "packages/google-maps-places": "0.1.23", - "packages/google-maps-routeoptimization": "0.1.7", - "packages/google-maps-routing": "0.6.13", - "packages/google-maps-solar": "0.1.5", - "packages/google-shopping-css": "0.1.12", - "packages/google-shopping-merchant-accounts": "0.2.3", - "packages/google-shopping-merchant-conversions": "0.1.6", - "packages/google-shopping-merchant-datasources": "0.1.7", - "packages/google-shopping-merchant-inventories": "0.1.12", - "packages/google-shopping-merchant-lfp": "0.1.6", - "packages/google-shopping-merchant-notifications": "0.1.5", - "packages/google-shopping-merchant-products": "0.2.0", - "packages/google-shopping-merchant-promotions": "0.1.5", - "packages/google-shopping-merchant-quota": "0.1.5", - "packages/google-shopping-merchant-reports": "0.1.12", - "packages/google-shopping-merchant-reviews": "0.1.0", - "packages/google-shopping-type": "0.1.9", - "packages/googleapis-common-protos": "1.67.0", - "packages/grafeas": "1.13.0", + "packages/google-maps-routeoptimization": "0.1.8", + "packages/google-maps-routing": "0.6.14", + "packages/google-maps-solar": "0.1.6", + "packages/google-shopping-css": "0.1.13", + "packages/google-shopping-merchant-accounts": "0.2.4", + "packages/google-shopping-merchant-conversions": "0.1.7", + "packages/google-shopping-merchant-datasources": "0.1.8", + "packages/google-shopping-merchant-inventories": "0.1.13", + "packages/google-shopping-merchant-lfp": "0.1.7", + "packages/google-shopping-merchant-notifications": "0.1.6", + "packages/google-shopping-merchant-products": "0.2.1", + "packages/google-shopping-merchant-promotions": "0.1.6", + "packages/google-shopping-merchant-quota": "0.1.6", + "packages/google-shopping-merchant-reports": "0.1.13", + "packages/google-shopping-merchant-reviews": "0.1.1", + "packages/google-shopping-type": "0.1.10", + "packages/googleapis-common-protos": "1.68.0", + "packages/grafeas": "1.14.0", "packages/grpc-google-iam-v1": "0.14.0" } diff --git a/packages/google-cloud-alloydb/CHANGELOG.md b/packages/google-cloud-alloydb/CHANGELOG.md index 8b23f1de8325..193e85cff1cd 100644 --- a/packages/google-cloud-alloydb/CHANGELOG.md +++ b/packages/google-cloud-alloydb/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.3](https://github.com/googleapis/google-cloud-python/compare/google-cloud-alloydb-v0.4.2...google-cloud-alloydb-v0.4.3) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.2](https://github.com/googleapis/google-cloud-python/compare/google-cloud-alloydb-v0.4.1...google-cloud-alloydb-v0.4.2) (2025-02-12) diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py index 558c8aab67c5..3a9c1a09b864 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.3" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py index 558c8aab67c5..3a9c1a09b864 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.3" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py index 558c8aab67c5..3a9c1a09b864 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.3" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py b/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py index 558c8aab67c5..3a9c1a09b864 100644 --- a/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py +++ b/packages/google-cloud-alloydb/google/cloud/alloydb_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.3" # {x-release-please-version} diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json index 93784dc7f2da..43b48cd898ee 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.1.0" + "version": "0.4.3" }, "snippets": [ { diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json index 0beca3926d06..24a6daaa32ca 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.1.0" + "version": "0.4.3" }, "snippets": [ { diff --git a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json index 696ffb3efe81..7d517e7e3cb6 100644 --- a/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json +++ b/packages/google-cloud-alloydb/samples/generated_samples/snippet_metadata_google.cloud.alloydb.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-alloydb", - "version": "0.1.0" + "version": "0.4.3" }, "snippets": [ { diff --git a/packages/google-cloud-apigee-registry/CHANGELOG.md b/packages/google-cloud-apigee-registry/CHANGELOG.md index cd8794a29972..b4a85794c0ca 100644 --- a/packages/google-cloud-apigee-registry/CHANGELOG.md +++ b/packages/google-cloud-apigee-registry/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.6.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apigee-registry-v0.6.15...google-cloud-apigee-registry-v0.6.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.6.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apigee-registry-v0.6.14...google-cloud-apigee-registry-v0.6.15) (2025-02-12) diff --git a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py index 558c8aab67c5..a22e7bbe7e4a 100644 --- a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py +++ b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.16" # {x-release-please-version} diff --git a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py index 558c8aab67c5..a22e7bbe7e4a 100644 --- a/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py +++ b/packages/google-cloud-apigee-registry/google/cloud/apigee_registry_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.16" # {x-release-please-version} diff --git a/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json b/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json index b2c5df756020..0a289d230bf2 100644 --- a/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json +++ b/packages/google-cloud-apigee-registry/samples/generated_samples/snippet_metadata_google.cloud.apigeeregistry.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-apigee-registry", - "version": "0.1.0" + "version": "0.6.16" }, "snippets": [ { diff --git a/packages/google-cloud-apphub/CHANGELOG.md b/packages/google-cloud-apphub/CHANGELOG.md index d60e8728a9b4..355c07eb12c5 100644 --- a/packages/google-cloud-apphub/CHANGELOG.md +++ b/packages/google-cloud-apphub/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apphub-v0.1.6...google-cloud-apphub-v0.1.7) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-cloud-apphub-v0.1.5...google-cloud-apphub-v0.1.6) (2025-02-12) diff --git a/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py b/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py +++ b/packages/google-cloud-apphub/google/cloud/apphub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py b/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py +++ b/packages/google-cloud-apphub/google/cloud/apphub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json b/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json index 161a57517820..4c74ec240edc 100644 --- a/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json +++ b/packages/google-cloud-apphub/samples/generated_samples/snippet_metadata_google.cloud.apphub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-apphub", - "version": "0.1.0" + "version": "0.1.7" }, "snippets": [ { diff --git a/packages/google-cloud-artifact-registry/CHANGELOG.md b/packages/google-cloud-artifact-registry/CHANGELOG.md index e920da3d5d43..af7df405c736 100644 --- a/packages/google-cloud-artifact-registry/CHANGELOG.md +++ b/packages/google-cloud-artifact-registry/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.15.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-artifact-registry-v1.15.0...google-cloud-artifact-registry-v1.15.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.15.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-artifact-registry-v1.14.0...google-cloud-artifact-registry-v1.15.0) (2025-02-12) diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py index 558c8aab67c5..2fd2bb1630b4 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.15.1" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py index 558c8aab67c5..2fd2bb1630b4 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.15.1" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py index 558c8aab67c5..2fd2bb1630b4 100644 --- a/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py +++ b/packages/google-cloud-artifact-registry/google/cloud/artifactregistry_v1beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.15.1" # {x-release-please-version} diff --git a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json index 43448eb993ec..0ebd4ca3c1d7 100644 --- a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json +++ b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-artifact-registry", - "version": "0.1.0" + "version": "1.15.1" }, "snippets": [ { diff --git a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json index 914e581f4fb1..840284cc16f0 100644 --- a/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json +++ b/packages/google-cloud-artifact-registry/samples/generated_samples/snippet_metadata_google.devtools.artifactregistry.v1beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-artifact-registry", - "version": "0.1.0" + "version": "1.15.1" }, "snippets": [ { diff --git a/packages/google-cloud-asset/CHANGELOG.md b/packages/google-cloud-asset/CHANGELOG.md index 408eb5815da4..462f5540f99e 100644 --- a/packages/google-cloud-asset/CHANGELOG.md +++ b/packages/google-cloud-asset/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-asset/#history +## [3.29.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-asset-v3.29.0...google-cloud-asset-v3.29.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [3.29.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-asset-v3.28.0...google-cloud-asset-v3.29.0) (2025-02-12) diff --git a/packages/google-cloud-asset/google/cloud/asset/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset/gapic_version.py index 558c8aab67c5..3cbfc540326b 100644 --- a/packages/google-cloud-asset/google/cloud/asset/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py index 558c8aab67c5..3cbfc540326b 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py index 558c8aab67c5..3cbfc540326b 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py index 558c8aab67c5..3cbfc540326b 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p2beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p4beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p4beta1/gapic_version.py index 16c2618143bb..e8d48a7113a7 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p4beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p4beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.29.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py b/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py index 558c8aab67c5..3cbfc540326b 100644 --- a/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py +++ b/packages/google-cloud-asset/google/cloud/asset_v1p5beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.29.1" # {x-release-please-version} diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json index 211efb19c2ad..c447f8100275 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.29.1" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json index 13d603d43770..c1ec29f88001 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.29.1" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json index abb0badfbf70..8449e9660ef6 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.29.1" }, "snippets": [ { diff --git a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json index 2b27b5681d7c..a0cde19334da 100644 --- a/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json +++ b/packages/google-cloud-asset/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.29.1" }, "snippets": [ { diff --git a/packages/google-cloud-automl/CHANGELOG.md b/packages/google-cloud-automl/CHANGELOG.md index a931c2c61a47..3bb1f78a64cc 100644 --- a/packages/google-cloud-automl/CHANGELOG.md +++ b/packages/google-cloud-automl/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-automl/#history +## [2.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-automl-v2.16.0...google-cloud-automl-v2.16.1) (2025-02-18) + + +### Bug Fixes + +* allow google-cloud-storage 3.x ([#13535](https://github.com/googleapis/google-cloud-python/issues/13535)) ([5dabf55](https://github.com/googleapis/google-cloud-python/commit/5dabf5556d505f55171344fd7c95384b8478e453)) + ## [2.16.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-automl-v2.15.0...google-cloud-automl-v2.16.0) (2025-02-12) diff --git a/packages/google-cloud-automl/google/cloud/automl/gapic_version.py b/packages/google-cloud-automl/google/cloud/automl/gapic_version.py index e154065d8da8..1230672bab9e 100644 --- a/packages/google-cloud-automl/google/cloud/automl/gapic_version.py +++ b/packages/google-cloud-automl/google/cloud/automl/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.16.0" # {x-release-please-version} +__version__ = "2.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-automl/google/cloud/automl_v1/gapic_version.py b/packages/google-cloud-automl/google/cloud/automl_v1/gapic_version.py index e154065d8da8..1230672bab9e 100644 --- a/packages/google-cloud-automl/google/cloud/automl_v1/gapic_version.py +++ b/packages/google-cloud-automl/google/cloud/automl_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.16.0" # {x-release-please-version} +__version__ = "2.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-automl/google/cloud/automl_v1beta1/gapic_version.py b/packages/google-cloud-automl/google/cloud/automl_v1beta1/gapic_version.py index e154065d8da8..1230672bab9e 100644 --- a/packages/google-cloud-automl/google/cloud/automl_v1beta1/gapic_version.py +++ b/packages/google-cloud-automl/google/cloud/automl_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.16.0" # {x-release-please-version} +__version__ = "2.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1.json b/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1.json index 87eb6ca88463..44c69a5b7aae 100644 --- a/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1.json +++ b/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-automl", - "version": "2.16.0" + "version": "2.16.1" }, "snippets": [ { diff --git a/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1beta1.json b/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1beta1.json index 65deff55ce68..e1a1afbdf39a 100644 --- a/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1beta1.json +++ b/packages/google-cloud-automl/samples/generated_samples/snippet_metadata_google.cloud.automl.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-automl", - "version": "2.16.0" + "version": "2.16.1" }, "snippets": [ { diff --git a/packages/google-cloud-backupdr/CHANGELOG.md b/packages/google-cloud-backupdr/CHANGELOG.md index 8f77993ddef8..445066f28f1b 100644 --- a/packages/google-cloud-backupdr/CHANGELOG.md +++ b/packages/google-cloud-backupdr/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.2.2](https://github.com/googleapis/google-cloud-python/compare/google-cloud-backupdr-v0.2.1...google-cloud-backupdr-v0.2.2) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.2.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-backupdr-v0.2.0...google-cloud-backupdr-v0.2.1) (2025-02-12) diff --git a/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py b/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py index 558c8aab67c5..d1a1a883babd 100644 --- a/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py +++ b/packages/google-cloud-backupdr/google/cloud/backupdr/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.2" # {x-release-please-version} diff --git a/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py b/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py index 558c8aab67c5..d1a1a883babd 100644 --- a/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py +++ b/packages/google-cloud-backupdr/google/cloud/backupdr_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.2" # {x-release-please-version} diff --git a/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json b/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json index 0f3972263529..b1c74a350331 100644 --- a/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json +++ b/packages/google-cloud-backupdr/samples/generated_samples/snippet_metadata_google.cloud.backupdr.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-backupdr", - "version": "0.1.0" + "version": "0.2.2" }, "snippets": [ { diff --git a/packages/google-cloud-bare-metal-solution/CHANGELOG.md b/packages/google-cloud-bare-metal-solution/CHANGELOG.md index 8e3e2ff8e942..bb1fd3988e90 100644 --- a/packages/google-cloud-bare-metal-solution/CHANGELOG.md +++ b/packages/google-cloud-bare-metal-solution/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.10.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bare-metal-solution-v1.10.0...google-cloud-bare-metal-solution-v1.10.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.10.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bare-metal-solution-v1.9.0...google-cloud-bare-metal-solution-v1.10.0) (2025-02-12) diff --git a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py index 558c8aab67c5..f1d827b5c728 100644 --- a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py +++ b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.10.1" # {x-release-please-version} diff --git a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py index 558c8aab67c5..f1d827b5c728 100644 --- a/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py +++ b/packages/google-cloud-bare-metal-solution/google/cloud/bare_metal_solution_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.10.1" # {x-release-please-version} diff --git a/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json b/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json index 2e341fc16178..6ec0afe89b63 100644 --- a/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json +++ b/packages/google-cloud-bare-metal-solution/samples/generated_samples/snippet_metadata_google.cloud.baremetalsolution.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bare-metal-solution", - "version": "0.1.0" + "version": "1.10.1" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md b/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md index 006b73838987..dd04ffe2496c 100644 --- a/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md +++ b/packages/google-cloud-beyondcorp-appconnections/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnections-v0.4.15...google-cloud-beyondcorp-appconnections-v0.4.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnections-v0.4.14...google-cloud-beyondcorp-appconnections-v0.4.15) (2025-02-12) diff --git a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnections/google/cloud/beyondcorp_appconnections_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json b/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json index f730a69adfa5..55d20b32008a 100644 --- a/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json +++ b/packages/google-cloud-beyondcorp-appconnections/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnections.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appconnections", - "version": "0.1.0" + "version": "0.4.16" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md b/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md index 7963fd5684c2..aa3ae85b8dc0 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md +++ b/packages/google-cloud-beyondcorp-appconnectors/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnectors-v0.4.15...google-cloud-beyondcorp-appconnectors-v0.4.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appconnectors-v0.4.14...google-cloud-beyondcorp-appconnectors-v0.4.15) (2025-02-12) diff --git a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appconnectors/google/cloud/beyondcorp_appconnectors_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json b/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json index e1535607b299..e734420e1b6c 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json +++ b/packages/google-cloud-beyondcorp-appconnectors/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appconnectors.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appconnectors", - "version": "0.1.0" + "version": "0.4.16" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md b/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md index e59a4b64d269..283b0d05edb2 100644 --- a/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md +++ b/packages/google-cloud-beyondcorp-appgateways/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appgateways-v0.4.15...google-cloud-beyondcorp-appgateways-v0.4.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-appgateways-v0.4.14...google-cloud-beyondcorp-appgateways-v0.4.15) (2025-02-12) diff --git a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-appgateways/google/cloud/beyondcorp_appgateways_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json b/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json index 0b3067b40e2b..a7a8d7e3f670 100644 --- a/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json +++ b/packages/google-cloud-beyondcorp-appgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.appgateways.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-appgateways", - "version": "0.1.0" + "version": "0.4.16" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md b/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md index 26bf9391cb96..85c9bc8986ac 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientconnectorservices-v0.4.15...google-cloud-beyondcorp-clientconnectorservices-v0.4.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientconnectorservices-v0.4.14...google-cloud-beyondcorp-clientconnectorservices-v0.4.15) (2025-02-12) diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/google/cloud/beyondcorp_clientconnectorservices_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json b/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json index e2e2d8f829d9..f849b5baf297 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientconnectorservices.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-clientconnectorservices", - "version": "0.1.0" + "version": "0.4.16" }, "snippets": [ { diff --git a/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md b/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md index f44507c56df6..fce3af01735f 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md +++ b/packages/google-cloud-beyondcorp-clientgateways/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientgateways-v0.4.14...google-cloud-beyondcorp-clientgateways-v0.4.15) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-beyondcorp-clientgateways-v0.4.13...google-cloud-beyondcorp-clientgateways-v0.4.14) (2025-02-12) diff --git a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py index 558c8aab67c5..49a0d50535a0 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.15" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py index 558c8aab67c5..49a0d50535a0 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py +++ b/packages/google-cloud-beyondcorp-clientgateways/google/cloud/beyondcorp_clientgateways_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.15" # {x-release-please-version} diff --git a/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json b/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json index 1aa87eed26ed..fd880e84f0b5 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json +++ b/packages/google-cloud-beyondcorp-clientgateways/samples/generated_samples/snippet_metadata_google.cloud.beyondcorp.clientgateways.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-beyondcorp-clientgateways", - "version": "0.1.0" + "version": "0.4.15" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md b/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md index e14d3d60d361..4c951a654e1c 100644 --- a/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md +++ b/packages/google-cloud-bigquery-analyticshub/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.4.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-analyticshub-v0.4.15...google-cloud-bigquery-analyticshub-v0.4.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.4.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-analyticshub-v0.4.14...google-cloud-bigquery-analyticshub-v0.4.15) (2025-02-12) diff --git a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py +++ b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py index 558c8aab67c5..dd30b4866aeb 100644 --- a/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-analyticshub/google/cloud/bigquery_analyticshub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.16" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json b/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json index 7d9e59976e72..b3a7d35c90ee 100644 --- a/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json +++ b/packages/google-cloud-bigquery-analyticshub/samples/generated_samples/snippet_metadata_google.cloud.bigquery.analyticshub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-analyticshub", - "version": "0.1.0" + "version": "0.4.16" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-connection/CHANGELOG.md b/packages/google-cloud-bigquery-connection/CHANGELOG.md index 13beee3c5abc..45e49ff5a526 100644 --- a/packages/google-cloud-bigquery-connection/CHANGELOG.md +++ b/packages/google-cloud-bigquery-connection/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-connection-v1.18.0...google-cloud-bigquery-connection-v1.18.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-connection-v1.17.0...google-cloud-bigquery-connection-v1.18.0) (2025-02-12) diff --git a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py +++ b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-connection/google/cloud/bigquery_connection_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json b/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json index a25b5a29d478..d7b6c2d22b78 100644 --- a/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json +++ b/packages/google-cloud-bigquery-connection/samples/generated_samples/snippet_metadata_google.cloud.bigquery.connection.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-connection", - "version": "0.1.0" + "version": "1.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md b/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md index 89484aa9d294..212da4d79d23 100644 --- a/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md +++ b/packages/google-cloud-bigquery-data-exchange/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.18](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-data-exchange-v0.5.17...google-cloud-bigquery-data-exchange-v0.5.18) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.5.17](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-data-exchange-v0.5.16...google-cloud-bigquery-data-exchange-v0.5.17) (2025-02-12) diff --git a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py index 558c8aab67c5..d26af44492c7 100644 --- a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py +++ b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.18" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py index 558c8aab67c5..d26af44492c7 100644 --- a/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py +++ b/packages/google-cloud-bigquery-data-exchange/google/cloud/bigquery_data_exchange_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.18" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json b/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json index 0103e35cd88a..0e7876665c9e 100644 --- a/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json +++ b/packages/google-cloud-bigquery-data-exchange/samples/generated_samples/snippet_metadata_google.cloud.bigquery.dataexchange.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-data-exchange", - "version": "0.1.0" + "version": "0.5.18" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md b/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md index b121035ff45a..7fc3295b96ce 100644 --- a/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md +++ b/packages/google-cloud-bigquery-datapolicies/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.6.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-datapolicies-v0.6.12...google-cloud-bigquery-datapolicies-v0.6.13) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.6.12](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-datapolicies-v0.6.11...google-cloud-bigquery-datapolicies-v0.6.12) (2025-02-12) diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py index 558c8aab67c5..b72badcc1eca 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.13" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py index 558c8aab67c5..b72badcc1eca 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.13" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py index 558c8aab67c5..b72badcc1eca 100644 --- a/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py +++ b/packages/google-cloud-bigquery-datapolicies/google/cloud/bigquery_datapolicies_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.13" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json index 8f3adb520dfb..9ab4a1ce09ed 100644 --- a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json +++ b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-datapolicies", - "version": "0.1.0" + "version": "0.6.13" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json index f5896d1aac3d..da54807d36c0 100644 --- a/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json +++ b/packages/google-cloud-bigquery-datapolicies/samples/generated_samples/snippet_metadata_google.cloud.bigquery.datapolicies.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-bigquery-datapolicies", - "version": "0.1.0" + "version": "0.6.13" }, "snippets": [ { diff --git a/packages/google-cloud-bigquery-logging/CHANGELOG.md b/packages/google-cloud-bigquery-logging/CHANGELOG.md index 86f4c3b0ed6f..4c3c2140feab 100644 --- a/packages/google-cloud-bigquery-logging/CHANGELOG.md +++ b/packages/google-cloud-bigquery-logging/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.6.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-logging-v1.6.0...google-cloud-bigquery-logging-v1.6.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.6.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-bigquery-logging-v1.5.0...google-cloud-bigquery-logging-v1.6.0) (2025-02-12) diff --git a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py index 558c8aab67c5..605cecd1f29e 100644 --- a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py +++ b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.6.1" # {x-release-please-version} diff --git a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py index 558c8aab67c5..605cecd1f29e 100644 --- a/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py +++ b/packages/google-cloud-bigquery-logging/google/cloud/bigquery_logging_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.6.1" # {x-release-please-version} diff --git a/packages/google-cloud-billing/CHANGELOG.md b/packages/google-cloud-billing/CHANGELOG.md index 70c741e12d23..1c61097eddab 100644 --- a/packages/google-cloud-billing/CHANGELOG.md +++ b/packages/google-cloud-billing/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-billing-v1.16.0...google-cloud-billing-v1.16.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.16.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-billing-v1.15.0...google-cloud-billing-v1.16.0) (2025-02-12) diff --git a/packages/google-cloud-billing/google/cloud/billing/gapic_version.py b/packages/google-cloud-billing/google/cloud/billing/gapic_version.py index 558c8aab67c5..b6e92d4eebd5 100644 --- a/packages/google-cloud-billing/google/cloud/billing/gapic_version.py +++ b/packages/google-cloud-billing/google/cloud/billing/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py b/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py index 558c8aab67c5..b6e92d4eebd5 100644 --- a/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py +++ b/packages/google-cloud-billing/google/cloud/billing_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json b/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json index 027b84af0571..8c3349fbbb1c 100644 --- a/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json +++ b/packages/google-cloud-billing/samples/generated_samples/snippet_metadata_google.cloud.billing.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-billing", - "version": "0.1.0" + "version": "1.16.1" }, "snippets": [ { diff --git a/packages/google-cloud-build/CHANGELOG.md b/packages/google-cloud-build/CHANGELOG.md index 2388460d8ef3..d4d6f911c7d6 100644 --- a/packages/google-cloud-build/CHANGELOG.md +++ b/packages/google-cloud-build/CHANGELOG.md @@ -4,6 +4,24 @@ [1]: https://pypi.org/project/google-cloud-build/#history +## [3.31.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-build-v3.30.0...google-cloud-build-v3.31.0) (2025-02-18) + + +### Features + +* Add option to enable fetching dependencies ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) +* Support for git proxy setup ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) + + +### Documentation + +* Updates to proto message comments ([3fe8899](https://github.com/googleapis/google-cloud-python/commit/3fe88999b3f56faeae0c8f36b4fe8f750d168f18)) + ## [3.30.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-build-v3.29.0...google-cloud-build-v3.30.0) (2025-02-12) diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild/gapic_version.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild/gapic_version.py index b154d635e33c..1502d62b51a8 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild/gapic_version.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.30.0" # {x-release-please-version} +__version__ = "3.31.0" # {x-release-please-version} diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/gapic_version.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/gapic_version.py index b154d635e33c..1502d62b51a8 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/gapic_version.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.30.0" # {x-release-please-version} +__version__ = "3.31.0" # {x-release-please-version} diff --git a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v2/gapic_version.py b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v2/gapic_version.py index b154d635e33c..1502d62b51a8 100644 --- a/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v2/gapic_version.py +++ b/packages/google-cloud-build/google/cloud/devtools/cloudbuild_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.30.0" # {x-release-please-version} +__version__ = "3.31.0" # {x-release-please-version} diff --git a/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v1.json b/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v1.json index 33a3513a412e..9dd562320b77 100644 --- a/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v1.json +++ b/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-build", - "version": "3.30.0" + "version": "3.31.0" }, "snippets": [ { diff --git a/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v2.json b/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v2.json index f364c6f47609..057a171ae7b2 100644 --- a/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v2.json +++ b/packages/google-cloud-build/samples/generated_samples/snippet_metadata_google.devtools.cloudbuild.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-build", - "version": "3.30.0" + "version": "3.31.0" }, "snippets": [ { diff --git a/packages/google-cloud-config/CHANGELOG.md b/packages/google-cloud-config/CHANGELOG.md index a9a66f6c039c..d6cfacae2a1a 100644 --- a/packages/google-cloud-config/CHANGELOG.md +++ b/packages/google-cloud-config/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-config-v0.1.15...google-cloud-config-v0.1.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [0.1.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-config-v0.1.14...google-cloud-config-v0.1.15) (2025-02-12) diff --git a/packages/google-cloud-config/google/cloud/config/gapic_version.py b/packages/google-cloud-config/google/cloud/config/gapic_version.py index 558c8aab67c5..5879ee6ab325 100644 --- a/packages/google-cloud-config/google/cloud/config/gapic_version.py +++ b/packages/google-cloud-config/google/cloud/config/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.16" # {x-release-please-version} diff --git a/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py b/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py index 558c8aab67c5..5879ee6ab325 100644 --- a/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py +++ b/packages/google-cloud-config/google/cloud/config_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.16" # {x-release-please-version} diff --git a/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json b/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json index e9c423a602a2..16c9cf7907d3 100644 --- a/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json +++ b/packages/google-cloud-config/samples/generated_samples/snippet_metadata_google.cloud.config.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-config", - "version": "0.1.0" + "version": "0.1.16" }, "snippets": [ { diff --git a/packages/google-cloud-contact-center-insights/CHANGELOG.md b/packages/google-cloud-contact-center-insights/CHANGELOG.md index 4a3142463e69..269e225ebd27 100644 --- a/packages/google-cloud-contact-center-insights/CHANGELOG.md +++ b/packages/google-cloud-contact-center-insights/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.23.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contact-center-insights-v1.23.0...google-cloud-contact-center-insights-v1.23.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([4571dff](https://github.com/googleapis/google-cloud-python/commit/4571dff9614843c6944c8568bd234c6ac5197218)) + ## [1.23.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contact-center-insights-v1.22.0...google-cloud-contact-center-insights-v1.23.0) (2025-02-12) diff --git a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py index 558c8aab67c5..2152db608ae5 100644 --- a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py +++ b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py index 558c8aab67c5..2152db608ae5 100644 --- a/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py +++ b/packages/google-cloud-contact-center-insights/google/cloud/contact_center_insights_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json b/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json index 53fac2587492..3a584dc20884 100644 --- a/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json +++ b/packages/google-cloud-contact-center-insights/samples/generated_samples/snippet_metadata_google.cloud.contactcenterinsights.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-contact-center-insights", - "version": "0.1.0" + "version": "1.23.1" }, "snippets": [ { diff --git a/packages/google-cloud-containeranalysis/CHANGELOG.md b/packages/google-cloud-containeranalysis/CHANGELOG.md index e98a2d8386e5..954b69829865 100644 --- a/packages/google-cloud-containeranalysis/CHANGELOG.md +++ b/packages/google-cloud-containeranalysis/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-containeranalysis-v2.17.0...google-cloud-containeranalysis-v2.17.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [2.17.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-containeranalysis-v2.16.0...google-cloud-containeranalysis-v2.17.0) (2025-02-12) diff --git a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py index 558c8aab67c5..6fecc94eb049 100644 --- a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py +++ b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py index 558c8aab67c5..6fecc94eb049 100644 --- a/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py +++ b/packages/google-cloud-containeranalysis/google/cloud/devtools/containeranalysis_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json b/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json index 07f9c39e95c2..653ae0dbe82b 100644 --- a/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json +++ b/packages/google-cloud-containeranalysis/samples/generated_samples/snippet_metadata_google.devtools.containeranalysis.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-containeranalysis", - "version": "0.1.0" + "version": "2.17.1" }, "snippets": [ { diff --git a/packages/google-cloud-contentwarehouse/CHANGELOG.md b/packages/google-cloud-contentwarehouse/CHANGELOG.md index 42e0a2de2956..7871bd6020ae 100644 --- a/packages/google-cloud-contentwarehouse/CHANGELOG.md +++ b/packages/google-cloud-contentwarehouse/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.7.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contentwarehouse-v0.7.13...google-cloud-contentwarehouse-v0.7.14) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [0.7.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-contentwarehouse-v0.7.12...google-cloud-contentwarehouse-v0.7.13) (2025-02-12) diff --git a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py index 558c8aab67c5..747954cc02fd 100644 --- a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py +++ b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.7.14" # {x-release-please-version} diff --git a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py index 558c8aab67c5..747954cc02fd 100644 --- a/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py +++ b/packages/google-cloud-contentwarehouse/google/cloud/contentwarehouse_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.7.14" # {x-release-please-version} diff --git a/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json b/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json index 3d6fe0e86ed6..2e6b6251b8b4 100644 --- a/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json +++ b/packages/google-cloud-contentwarehouse/samples/generated_samples/snippet_metadata_google.cloud.contentwarehouse.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-contentwarehouse", - "version": "0.1.0" + "version": "0.7.14" }, "snippets": [ { diff --git a/packages/google-cloud-data-fusion/CHANGELOG.md b/packages/google-cloud-data-fusion/CHANGELOG.md index f484ccaa8be1..479d7e7d782c 100644 --- a/packages/google-cloud-data-fusion/CHANGELOG.md +++ b/packages/google-cloud-data-fusion/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-data-fusion-v1.13.0...google-cloud-data-fusion-v1.13.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-data-fusion-v1.12.0...google-cloud-data-fusion-v1.13.0) (2025-02-12) diff --git a/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py b/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py +++ b/packages/google-cloud-data-fusion/google/cloud/data_fusion/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py b/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py +++ b/packages/google-cloud-data-fusion/google/cloud/data_fusion_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json b/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json index fce0307055b9..2f71f3c0d9eb 100644 --- a/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json +++ b/packages/google-cloud-data-fusion/samples/generated_samples/snippet_metadata_google.cloud.datafusion.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-data-fusion", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-datacatalog/CHANGELOG.md b/packages/google-cloud-datacatalog/CHANGELOG.md index 638e699d0263..84742a854d74 100644 --- a/packages/google-cloud-datacatalog/CHANGELOG.md +++ b/packages/google-cloud-datacatalog/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-datacatalog/#history +## [3.25.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datacatalog-v3.25.0...google-cloud-datacatalog-v3.25.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [3.25.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datacatalog-v3.24.1...google-cloud-datacatalog-v3.25.0) (2025-02-12) diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py index 558c8aab67c5..bebbb5e47648 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.25.1" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py index 558c8aab67c5..bebbb5e47648 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.25.1" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py index 558c8aab67c5..bebbb5e47648 100644 --- a/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py +++ b/packages/google-cloud-datacatalog/google/cloud/datacatalog_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.25.1" # {x-release-please-version} diff --git a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json index e1bfcdcf1b01..d75f700b54e7 100644 --- a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json +++ b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datacatalog", - "version": "0.1.0" + "version": "3.25.1" }, "snippets": [ { diff --git a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json index f2e225c6cf60..df76910ea602 100644 --- a/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json +++ b/packages/google-cloud-datacatalog/samples/generated_samples/snippet_metadata_google.cloud.datacatalog.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datacatalog", - "version": "0.1.0" + "version": "3.25.1" }, "snippets": [ { diff --git a/packages/google-cloud-dataform/CHANGELOG.md b/packages/google-cloud-dataform/CHANGELOG.md index f998faf7db56..7ca701f1248e 100644 --- a/packages/google-cloud-dataform/CHANGELOG.md +++ b/packages/google-cloud-dataform/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataform-v0.5.15...google-cloud-dataform-v0.5.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [0.5.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataform-v0.5.14...google-cloud-dataform-v0.5.15) (2025-02-12) diff --git a/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py b/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py index 558c8aab67c5..02b0cbec08ac 100644 --- a/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py +++ b/packages/google-cloud-dataform/google/cloud/dataform/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.16" # {x-release-please-version} diff --git a/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py b/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py index 558c8aab67c5..02b0cbec08ac 100644 --- a/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py +++ b/packages/google-cloud-dataform/google/cloud/dataform_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.16" # {x-release-please-version} diff --git a/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json b/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json index 1a184ef105a8..a013df09ca7f 100644 --- a/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json +++ b/packages/google-cloud-dataform/samples/generated_samples/snippet_metadata_google.cloud.dataform.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataform", - "version": "0.1.0" + "version": "0.5.16" }, "snippets": [ { diff --git a/packages/google-cloud-dataplex/CHANGELOG.md b/packages/google-cloud-dataplex/CHANGELOG.md index a6421a792bd4..83243b5b378d 100644 --- a/packages/google-cloud-dataplex/CHANGELOG.md +++ b/packages/google-cloud-dataplex/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.7.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataplex-v2.7.0...google-cloud-dataplex-v2.7.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [2.7.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataplex-v2.6.0...google-cloud-dataplex-v2.7.0) (2025-02-12) diff --git a/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py b/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py index 558c8aab67c5..d0231c6255cd 100644 --- a/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py +++ b/packages/google-cloud-dataplex/google/cloud/dataplex/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.7.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py b/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py index 558c8aab67c5..d0231c6255cd 100644 --- a/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py +++ b/packages/google-cloud-dataplex/google/cloud/dataplex_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.7.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json b/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json index ad778f70e58f..d01b8bd1e061 100644 --- a/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json +++ b/packages/google-cloud-dataplex/samples/generated_samples/snippet_metadata_google.cloud.dataplex.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataplex", - "version": "0.1.0" + "version": "2.7.1" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/CHANGELOG.md b/packages/google-cloud-dataproc-metastore/CHANGELOG.md index f8e11020dd54..901e2f063a57 100644 --- a/packages/google-cloud-dataproc-metastore/CHANGELOG.md +++ b/packages/google-cloud-dataproc-metastore/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-metastore-v1.18.0...google-cloud-dataproc-metastore-v1.18.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-metastore-v1.17.0...google-cloud-dataproc-metastore-v1.18.0) (2025-02-12) diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py index 558c8aab67c5..ef9777764da2 100644 --- a/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py +++ b/packages/google-cloud-dataproc-metastore/google/cloud/metastore_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json index a1409ff0b020..830a78139a35 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "0.1.0" + "version": "1.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json index 2e7667ce048f..9d82d03fb5a5 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "0.1.0" + "version": "1.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json index 8f741b2fab3f..04d498225736 100644 --- a/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json +++ b/packages/google-cloud-dataproc-metastore/samples/generated_samples/snippet_metadata_google.cloud.metastore.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc-metastore", - "version": "0.1.0" + "version": "1.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-dataproc/CHANGELOG.md b/packages/google-cloud-dataproc/CHANGELOG.md index db51f804bed3..2c0b770ccbd1 100644 --- a/packages/google-cloud-dataproc/CHANGELOG.md +++ b/packages/google-cloud-dataproc/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-dataproc/#history +## [5.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-v5.17.0...google-cloud-dataproc-v5.17.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [5.17.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dataproc-v5.16.0...google-cloud-dataproc-v5.17.0) (2025-02-12) diff --git a/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py b/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py index 558c8aab67c5..615f503c8e3e 100644 --- a/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py +++ b/packages/google-cloud-dataproc/google/cloud/dataproc/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "5.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py b/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py index 558c8aab67c5..615f503c8e3e 100644 --- a/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py +++ b/packages/google-cloud-dataproc/google/cloud/dataproc_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "5.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json b/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json index 0b7171f0c4e8..4fe7c3dc9ac4 100644 --- a/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json +++ b/packages/google-cloud-dataproc/samples/generated_samples/snippet_metadata_google.cloud.dataproc.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dataproc", - "version": "0.1.0" + "version": "5.17.1" }, "snippets": [ { diff --git a/packages/google-cloud-datastream/CHANGELOG.md b/packages/google-cloud-datastream/CHANGELOG.md index e952b75d55b7..cd4a8fbf0ac0 100644 --- a/packages/google-cloud-datastream/CHANGELOG.md +++ b/packages/google-cloud-datastream/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datastream-v1.13.0...google-cloud-datastream-v1.13.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-datastream-v1.12.0...google-cloud-datastream-v1.13.0) (2025-02-12) diff --git a/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py b/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py +++ b/packages/google-cloud-datastream/google/cloud/datastream_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json index c35515ccf4ca..ebde03e6cf32 100644 --- a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json +++ b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datastream", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json index 8ecc74dc7276..5b48b10a551b 100644 --- a/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json +++ b/packages/google-cloud-datastream/samples/generated_samples/snippet_metadata_google.cloud.datastream.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-datastream", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-deploy/CHANGELOG.md b/packages/google-cloud-deploy/CHANGELOG.md index b7ec50c392be..0d50ee2010b4 100644 --- a/packages/google-cloud-deploy/CHANGELOG.md +++ b/packages/google-cloud-deploy/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.6.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-deploy-v2.6.0...google-cloud-deploy-v2.6.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [2.6.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-deploy-v2.5.0...google-cloud-deploy-v2.6.0) (2025-02-12) diff --git a/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py b/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py index 558c8aab67c5..5a75430e8709 100644 --- a/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py +++ b/packages/google-cloud-deploy/google/cloud/deploy/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.6.1" # {x-release-please-version} diff --git a/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py b/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py index 558c8aab67c5..5a75430e8709 100644 --- a/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py +++ b/packages/google-cloud-deploy/google/cloud/deploy_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.6.1" # {x-release-please-version} diff --git a/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json b/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json index c29c8f123304..7c8f7d7f4d02 100644 --- a/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json +++ b/packages/google-cloud-deploy/samples/generated_samples/snippet_metadata_google.cloud.deploy.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-deploy", - "version": "0.1.0" + "version": "2.6.1" }, "snippets": [ { diff --git a/packages/google-cloud-dms/CHANGELOG.md b/packages/google-cloud-dms/CHANGELOG.md index 16bd97e9455d..59454112727d 100644 --- a/packages/google-cloud-dms/CHANGELOG.md +++ b/packages/google-cloud-dms/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.12.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dms-v1.12.0...google-cloud-dms-v1.12.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.12.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-dms-v1.11.0...google-cloud-dms-v1.12.0) (2025-02-12) diff --git a/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py b/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py index 558c8aab67c5..49ddc22ee702 100644 --- a/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py +++ b/packages/google-cloud-dms/google/cloud/clouddms/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.12.1" # {x-release-please-version} diff --git a/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py b/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py index 558c8aab67c5..49ddc22ee702 100644 --- a/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py +++ b/packages/google-cloud-dms/google/cloud/clouddms_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.12.1" # {x-release-please-version} diff --git a/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json b/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json index c26f7e5a0532..3c5f79757ebb 100644 --- a/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json +++ b/packages/google-cloud-dms/samples/generated_samples/snippet_metadata_google.cloud.clouddms.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dms", - "version": "0.1.0" + "version": "1.12.1" }, "snippets": [ { diff --git a/packages/google-cloud-eventarc/CHANGELOG.md b/packages/google-cloud-eventarc/CHANGELOG.md index b05efbf7e450..651dd7c7404c 100644 --- a/packages/google-cloud-eventarc/CHANGELOG.md +++ b/packages/google-cloud-eventarc/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.15.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-eventarc-v1.15.0...google-cloud-eventarc-v1.15.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.15.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-eventarc-v1.14.0...google-cloud-eventarc-v1.15.0) (2025-02-12) diff --git a/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py b/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py index 558c8aab67c5..2fd2bb1630b4 100644 --- a/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py +++ b/packages/google-cloud-eventarc/google/cloud/eventarc/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.15.1" # {x-release-please-version} diff --git a/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py b/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py index 558c8aab67c5..2fd2bb1630b4 100644 --- a/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py +++ b/packages/google-cloud-eventarc/google/cloud/eventarc_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.15.1" # {x-release-please-version} diff --git a/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json b/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json index 73d35229f306..f53320d853cf 100644 --- a/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json +++ b/packages/google-cloud-eventarc/samples/generated_samples/snippet_metadata_google.cloud.eventarc.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-eventarc", - "version": "0.1.0" + "version": "1.15.1" }, "snippets": [ { diff --git a/packages/google-cloud-functions/CHANGELOG.md b/packages/google-cloud-functions/CHANGELOG.md index 42162abe5c6c..a0ddaf1d0ca9 100644 --- a/packages/google-cloud-functions/CHANGELOG.md +++ b/packages/google-cloud-functions/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.20.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-functions-v1.20.0...google-cloud-functions-v1.20.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.20.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-functions-v1.19.0...google-cloud-functions-v1.20.0) (2025-02-12) diff --git a/packages/google-cloud-functions/google/cloud/functions/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions/gapic_version.py index 558c8aab67c5..4da8c821edb1 100644 --- a/packages/google-cloud-functions/google/cloud/functions/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py index 558c8aab67c5..4da8c821edb1 100644 --- a/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py b/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py index 558c8aab67c5..4da8c821edb1 100644 --- a/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py +++ b/packages/google-cloud-functions/google/cloud/functions_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json index 7051120dab3b..7f0ed8c067e4 100644 --- a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json +++ b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-functions", - "version": "0.1.0" + "version": "1.20.1" }, "snippets": [ { diff --git a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json index eea3a0edf2a1..cf1103c6a41d 100644 --- a/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json +++ b/packages/google-cloud-functions/samples/generated_samples/snippet_metadata_google.cloud.functions.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-functions", - "version": "0.1.0" + "version": "1.20.1" }, "snippets": [ { diff --git a/packages/google-cloud-gke-backup/CHANGELOG.md b/packages/google-cloud-gke-backup/CHANGELOG.md index 68b1dbbfa5ae..a5536b31caba 100644 --- a/packages/google-cloud-gke-backup/CHANGELOG.md +++ b/packages/google-cloud-gke-backup/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-backup-v0.5.15...google-cloud-gke-backup-v0.5.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [0.5.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-backup-v0.5.14...google-cloud-gke-backup-v0.5.15) (2025-02-12) diff --git a/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py b/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py index 558c8aab67c5..02b0cbec08ac 100644 --- a/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py +++ b/packages/google-cloud-gke-backup/google/cloud/gke_backup/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.16" # {x-release-please-version} diff --git a/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py b/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py index 558c8aab67c5..02b0cbec08ac 100644 --- a/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py +++ b/packages/google-cloud-gke-backup/google/cloud/gke_backup_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.16" # {x-release-please-version} diff --git a/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json b/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json index ae88d4785854..43f1dbb385d4 100644 --- a/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json +++ b/packages/google-cloud-gke-backup/samples/generated_samples/snippet_metadata_google.cloud.gkebackup.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-backup", - "version": "0.1.0" + "version": "0.5.16" }, "snippets": [ { diff --git a/packages/google-cloud-gke-hub/CHANGELOG.md b/packages/google-cloud-gke-hub/CHANGELOG.md index 5413e7fde20b..c9b8727c6618 100644 --- a/packages/google-cloud-gke-hub/CHANGELOG.md +++ b/packages/google-cloud-gke-hub/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.17.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-hub-v1.17.0...google-cloud-gke-hub-v1.17.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.17.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-gke-hub-v1.16.0...google-cloud-gke-hub-v1.17.0) (2025-02-12) diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py index 558c8aab67c5..f6f018380cd7 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py index 558c8aab67c5..f6f018380cd7 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/configmanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py index 558c8aab67c5..f6f018380cd7 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py index 558c8aab67c5..f6f018380cd7 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1/multiclusteringress_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py index 558c8aab67c5..f6f018380cd7 100644 --- a/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py +++ b/packages/google-cloud-gke-hub/google/cloud/gkehub_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.17.1" # {x-release-please-version} diff --git a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json index 0e22653d9aa3..d8d8262ebae2 100644 --- a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json +++ b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-hub", - "version": "0.1.0" + "version": "1.17.1" }, "snippets": [ { diff --git a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json index c8aed2f9f17d..85b5bf117a90 100644 --- a/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json +++ b/packages/google-cloud-gke-hub/samples/generated_samples/snippet_metadata_google.cloud.gkehub.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-gke-hub", - "version": "0.1.0" + "version": "1.17.1" }, "snippets": [ { diff --git a/packages/google-cloud-iam-logging/CHANGELOG.md b/packages/google-cloud-iam-logging/CHANGELOG.md index 791332b6e379..fa292954a09d 100644 --- a/packages/google-cloud-iam-logging/CHANGELOG.md +++ b/packages/google-cloud-iam-logging/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.4.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-logging-v1.4.0...google-cloud-iam-logging-v1.4.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.4.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-logging-v1.3.5...google-cloud-iam-logging-v1.4.0) (2024-10-24) diff --git a/packages/google-cloud-iam-logging/google/cloud/iam_logging/gapic_version.py b/packages/google-cloud-iam-logging/google/cloud/iam_logging/gapic_version.py index 558c8aab67c5..3c29aa2a92e3 100644 --- a/packages/google-cloud-iam-logging/google/cloud/iam_logging/gapic_version.py +++ b/packages/google-cloud-iam-logging/google/cloud/iam_logging/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.4.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam-logging/google/cloud/iam_logging_v1/gapic_version.py b/packages/google-cloud-iam-logging/google/cloud/iam_logging_v1/gapic_version.py index 558c8aab67c5..3c29aa2a92e3 100644 --- a/packages/google-cloud-iam-logging/google/cloud/iam_logging_v1/gapic_version.py +++ b/packages/google-cloud-iam-logging/google/cloud/iam_logging_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.4.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/CHANGELOG.md b/packages/google-cloud-iam/CHANGELOG.md index 3c76fb84e230..9f8da92fefd9 100644 --- a/packages/google-cloud-iam/CHANGELOG.md +++ b/packages/google-cloud-iam/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-iam/#history +## [2.18.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-v2.18.0...google-cloud-iam-v2.18.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [2.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-v2.17.0...google-cloud-iam-v2.18.0) (2025-02-12) diff --git a/packages/google-cloud-iam/google/cloud/iam/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_admin/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_admin_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_credentials/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_credentials_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py b/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py index 558c8aab67c5..cd54f00b65f5 100644 --- a/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py +++ b/packages/google-cloud-iam/google/cloud/iam_v2beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.1" # {x-release-please-version} diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json index 0fa605b91500..184b17adc9f8 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.admin.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "0.1.0" + "version": "2.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json index 0809777f1998..4faf96f1d331 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.credentials.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "0.1.0" + "version": "2.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json index 5b79ae802abe..f082f41d287a 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "0.1.0" + "version": "2.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json index 5b3b08a7e2fc..fb6140a8361c 100644 --- a/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json +++ b/packages/google-cloud-iam/samples/generated_samples/snippet_metadata_google.iam.v2beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iam", - "version": "0.1.0" + "version": "2.18.1" }, "snippets": [ { diff --git a/packages/google-cloud-iap/CHANGELOG.md b/packages/google-cloud-iap/CHANGELOG.md index 1a00ebfa71d8..a1c9516f78d5 100644 --- a/packages/google-cloud-iap/CHANGELOG.md +++ b/packages/google-cloud-iap/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.16.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iap-v1.16.0...google-cloud-iap-v1.16.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [1.16.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iap-v1.15.0...google-cloud-iap-v1.16.0) (2025-02-12) diff --git a/packages/google-cloud-iap/google/cloud/iap/gapic_version.py b/packages/google-cloud-iap/google/cloud/iap/gapic_version.py index 558c8aab67c5..b6e92d4eebd5 100644 --- a/packages/google-cloud-iap/google/cloud/iap/gapic_version.py +++ b/packages/google-cloud-iap/google/cloud/iap/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py b/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py index 558c8aab67c5..b6e92d4eebd5 100644 --- a/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py +++ b/packages/google-cloud-iap/google/cloud/iap_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.16.1" # {x-release-please-version} diff --git a/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json b/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json index e4e6134926e0..9b6cab2366cc 100644 --- a/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json +++ b/packages/google-cloud-iap/samples/generated_samples/snippet_metadata_google.cloud.iap.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-iap", - "version": "0.1.0" + "version": "1.16.1" }, "snippets": [ { diff --git a/packages/google-cloud-kms/CHANGELOG.md b/packages/google-cloud-kms/CHANGELOG.md index c1fb061f940e..71d3fe380f0e 100644 --- a/packages/google-cloud-kms/CHANGELOG.md +++ b/packages/google-cloud-kms/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-kms/#history +## [3.3.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-kms-v3.3.0...google-cloud-kms-v3.3.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [3.3.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-kms-v3.2.2...google-cloud-kms-v3.3.0) (2025-02-12) diff --git a/packages/google-cloud-kms/google/cloud/kms/gapic_version.py b/packages/google-cloud-kms/google/cloud/kms/gapic_version.py index 558c8aab67c5..9994a27c8380 100644 --- a/packages/google-cloud-kms/google/cloud/kms/gapic_version.py +++ b/packages/google-cloud-kms/google/cloud/kms/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.3.1" # {x-release-please-version} diff --git a/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py b/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py index 558c8aab67c5..9994a27c8380 100644 --- a/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py +++ b/packages/google-cloud-kms/google/cloud/kms_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.3.1" # {x-release-please-version} diff --git a/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json b/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json index 31292c269f5b..c5531d41299f 100644 --- a/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json +++ b/packages/google-cloud-kms/samples/generated_samples/snippet_metadata_google.cloud.kms.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-kms", - "version": "0.1.0" + "version": "3.3.1" }, "snippets": [ { diff --git a/packages/google-cloud-network-connectivity/CHANGELOG.md b/packages/google-cloud-network-connectivity/CHANGELOG.md index c8b5ae941b41..4aea772dbb4c 100644 --- a/packages/google-cloud-network-connectivity/CHANGELOG.md +++ b/packages/google-cloud-network-connectivity/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.7.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-connectivity-v2.7.0...google-cloud-network-connectivity-v2.7.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([16e14c8](https://github.com/googleapis/google-cloud-python/commit/16e14c8d547864360dcab45d90e9e55169204fc6)) + ## [2.7.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-connectivity-v2.6.0...google-cloud-network-connectivity-v2.7.0) (2025-02-12) diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py index 558c8aab67c5..d0231c6255cd 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.7.1" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py index 558c8aab67c5..d0231c6255cd 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.7.1" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py index 558c8aab67c5..d0231c6255cd 100644 --- a/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py +++ b/packages/google-cloud-network-connectivity/google/cloud/networkconnectivity_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.7.1" # {x-release-please-version} diff --git a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json index 8d620f5c261f..da1bbf608a93 100644 --- a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json +++ b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-connectivity", - "version": "0.1.0" + "version": "2.7.1" }, "snippets": [ { diff --git a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json index 780180f11887..db2ba98de078 100644 --- a/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json +++ b/packages/google-cloud-network-connectivity/samples/generated_samples/snippet_metadata_google.cloud.networkconnectivity.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-connectivity", - "version": "0.1.0" + "version": "2.7.1" }, "snippets": [ { diff --git a/packages/google-cloud-network-management/CHANGELOG.md b/packages/google-cloud-network-management/CHANGELOG.md index f7189fd838f5..d738d4dd7ce3 100644 --- a/packages/google-cloud-network-management/CHANGELOG.md +++ b/packages/google-cloud-network-management/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.25.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-management-v1.25.0...google-cloud-network-management-v1.25.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.25.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-management-v1.24.0...google-cloud-network-management-v1.25.0) (2025-02-12) diff --git a/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py b/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py index 558c8aab67c5..830f74898cc0 100644 --- a/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py +++ b/packages/google-cloud-network-management/google/cloud/network_management/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.1" # {x-release-please-version} diff --git a/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py b/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py index 558c8aab67c5..830f74898cc0 100644 --- a/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py +++ b/packages/google-cloud-network-management/google/cloud/network_management_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.1" # {x-release-please-version} diff --git a/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json b/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json index 7bedd05e20b0..dd8bf8a20f3b 100644 --- a/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json +++ b/packages/google-cloud-network-management/samples/generated_samples/snippet_metadata_google.cloud.networkmanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-management", - "version": "0.1.0" + "version": "1.25.1" }, "snippets": [ { diff --git a/packages/google-cloud-network-security/CHANGELOG.md b/packages/google-cloud-network-security/CHANGELOG.md index f897dfb9375f..654e8c734178 100644 --- a/packages/google-cloud-network-security/CHANGELOG.md +++ b/packages/google-cloud-network-security/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.9.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-security-v0.9.15...google-cloud-network-security-v0.9.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.9.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-security-v0.9.14...google-cloud-network-security-v0.9.15) (2025-02-12) diff --git a/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py index 558c8aab67c5..5d73c1716ca4 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.9.16" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py index 558c8aab67c5..5d73c1716ca4 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.9.16" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py b/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py index 558c8aab67c5..5d73c1716ca4 100644 --- a/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py +++ b/packages/google-cloud-network-security/google/cloud/network_security_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.9.16" # {x-release-please-version} diff --git a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json index 71edaea2e319..904d505ffb7d 100644 --- a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json +++ b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-security", - "version": "0.1.0" + "version": "0.9.16" }, "snippets": [ { diff --git a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json index 71c9b6489c86..46e993db37e8 100644 --- a/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json +++ b/packages/google-cloud-network-security/samples/generated_samples/snippet_metadata_google.cloud.networksecurity.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-security", - "version": "0.1.0" + "version": "0.9.16" }, "snippets": [ { diff --git a/packages/google-cloud-network-services/CHANGELOG.md b/packages/google-cloud-network-services/CHANGELOG.md index 7f5ff9801933..dbd155515788 100644 --- a/packages/google-cloud-network-services/CHANGELOG.md +++ b/packages/google-cloud-network-services/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.19](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-services-v0.5.18...google-cloud-network-services-v0.5.19) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.5.18](https://github.com/googleapis/google-cloud-python/compare/google-cloud-network-services-v0.5.17...google-cloud-network-services-v0.5.18) (2025-02-12) diff --git a/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py b/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py index 558c8aab67c5..0360ff7f1800 100644 --- a/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py +++ b/packages/google-cloud-network-services/google/cloud/network_services/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.19" # {x-release-please-version} diff --git a/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py b/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py index 558c8aab67c5..0360ff7f1800 100644 --- a/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py +++ b/packages/google-cloud-network-services/google/cloud/network_services_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.19" # {x-release-please-version} diff --git a/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json b/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json index c9caccff1bd4..2043ed300884 100644 --- a/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json +++ b/packages/google-cloud-network-services/samples/generated_samples/snippet_metadata_google.cloud.networkservices.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-network-services", - "version": "0.1.0" + "version": "0.5.19" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/CHANGELOG.md b/packages/google-cloud-notebooks/CHANGELOG.md index 36fa46346e18..2b21fe7dd38f 100644 --- a/packages/google-cloud-notebooks/CHANGELOG.md +++ b/packages/google-cloud-notebooks/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-notebooks-v1.13.0...google-cloud-notebooks-v1.13.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-notebooks-v1.12.0...google-cloud-notebooks-v1.13.0) (2025-02-12) diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py b/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py +++ b/packages/google-cloud-notebooks/google/cloud/notebooks_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json index 220b755f8ced..5ec008a0b2f4 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json index 508ef241d01c..43bc1d09e586 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json index 11d18ed44573..8e4a69d4c98a 100644 --- a/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json +++ b/packages/google-cloud-notebooks/samples/generated_samples/snippet_metadata_google.cloud.notebooks.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-notebooks", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-parallelstore/CHANGELOG.md b/packages/google-cloud-parallelstore/CHANGELOG.md index 739b72ce95a9..56ca22b0ed9e 100644 --- a/packages/google-cloud-parallelstore/CHANGELOG.md +++ b/packages/google-cloud-parallelstore/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [0.2.11](https://github.com/googleapis/google-cloud-python/compare/google-cloud-parallelstore-v0.2.10...google-cloud-parallelstore-v0.2.11) (2025-02-18) + + +### Features + +* Adding `deployment_type` field ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) +* deprecating `daos_version` field ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) + + +### Documentation + +* updated `directory_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is now immutable ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) +* updated documentation for field `daos_version` in message `.google.cloud.parallelstore.v1.Instance` to reflect that the field is deprecated. ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) +* Updated field `file_stripe_level` in message `.google.cloud.parallelstore.v1.Instance` to reflected that message is now immutable ([03649eb](https://github.com/googleapis/google-cloud-python/commit/03649eb7f4b41de2981b1d49e7a6fc2bf20686d1)) + ## [0.2.10](https://github.com/googleapis/google-cloud-python/compare/google-cloud-parallelstore-v0.2.9...google-cloud-parallelstore-v0.2.10) (2025-02-12) diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py index 558c8aab67c5..8666a5d9aaba 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.11" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py index 558c8aab67c5..8666a5d9aaba 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.11" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py index 558c8aab67c5..8666a5d9aaba 100644 --- a/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py +++ b/packages/google-cloud-parallelstore/google/cloud/parallelstore_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.11" # {x-release-please-version} diff --git a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json index 30bc2a5b8355..27a991e2468e 100644 --- a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json +++ b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-parallelstore", - "version": "0.1.0" + "version": "0.2.11" }, "snippets": [ { diff --git a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json index db5492278bf9..6258dafa6af8 100644 --- a/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json +++ b/packages/google-cloud-parallelstore/samples/generated_samples/snippet_metadata_google.cloud.parallelstore.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-parallelstore", - "version": "0.1.0" + "version": "0.2.11" }, "snippets": [ { diff --git a/packages/google-cloud-parametermanager/CHANGELOG.md b/packages/google-cloud-parametermanager/CHANGELOG.md index 85b820b803ee..b734d7307496 100644 --- a/packages/google-cloud-parametermanager/CHANGELOG.md +++ b/packages/google-cloud-parametermanager/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-parametermanager-v0.1.0...google-cloud-parametermanager-v0.1.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## 0.1.0 (2025-01-20) diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py index 558c8aab67c5..0c7cc68730c4 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.1" # {x-release-please-version} diff --git a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py index 558c8aab67c5..0c7cc68730c4 100644 --- a/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py +++ b/packages/google-cloud-parametermanager/google/cloud/parametermanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.1" # {x-release-please-version} diff --git a/packages/google-cloud-parametermanager/samples/generated_samples/snippet_metadata_google.cloud.parametermanager.v1.json b/packages/google-cloud-parametermanager/samples/generated_samples/snippet_metadata_google.cloud.parametermanager.v1.json index b00178e5c05f..cbb4927925e5 100644 --- a/packages/google-cloud-parametermanager/samples/generated_samples/snippet_metadata_google.cloud.parametermanager.v1.json +++ b/packages/google-cloud-parametermanager/samples/generated_samples/snippet_metadata_google.cloud.parametermanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-parametermanager", - "version": "0.1.0" + "version": "0.1.1" }, "snippets": [ { diff --git a/packages/google-cloud-phishing-protection/CHANGELOG.md b/packages/google-cloud-phishing-protection/CHANGELOG.md index fc7447e69bc7..a1d9391f869f 100644 --- a/packages/google-cloud-phishing-protection/CHANGELOG.md +++ b/packages/google-cloud-phishing-protection/CHANGELOG.md @@ -5,6 +5,14 @@ [1]: https://pypi.org/project/google-cloud-phishing-protection/#history +## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-phishing-protection-v1.13.0...google-cloud-phishing-protection-v1.14.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-phishing-protection-v1.12.1...google-cloud-phishing-protection-v1.13.0) (2024-12-12) diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py index 558c8aab67c5..2159c8af6f8e 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.0" # {x-release-please-version} diff --git a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py index 558c8aab67c5..2159c8af6f8e 100644 --- a/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py +++ b/packages/google-cloud-phishing-protection/google/cloud/phishingprotection_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.0" # {x-release-please-version} diff --git a/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json b/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json index 18460381eb04..37e69d845674 100644 --- a/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json +++ b/packages/google-cloud-phishing-protection/samples/generated_samples/snippet_metadata_google.cloud.phishingprotection.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-phishing-protection", - "version": "0.1.0" + "version": "1.14.0" }, "snippets": [ { diff --git a/packages/google-cloud-policy-troubleshooter/CHANGELOG.md b/packages/google-cloud-policy-troubleshooter/CHANGELOG.md index 0c6ad9cbdec0..30c43f4fca20 100644 --- a/packages/google-cloud-policy-troubleshooter/CHANGELOG.md +++ b/packages/google-cloud-policy-troubleshooter/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policy-troubleshooter-v1.13.0...google-cloud-policy-troubleshooter-v1.13.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policy-troubleshooter-v1.12.1...google-cloud-policy-troubleshooter-v1.13.0) (2024-12-12) diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py +++ b/packages/google-cloud-policy-troubleshooter/google/cloud/policytroubleshooter_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json b/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json index 24a7fb5b901c..73f27c6a91f0 100644 --- a/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json +++ b/packages/google-cloud-policy-troubleshooter/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policy-troubleshooter", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-policysimulator/CHANGELOG.md b/packages/google-cloud-policysimulator/CHANGELOG.md index 4665f4e199f7..55c9ef7878ea 100644 --- a/packages/google-cloud-policysimulator/CHANGELOG.md +++ b/packages/google-cloud-policysimulator/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policysimulator-v0.1.11...google-cloud-policysimulator-v0.1.12) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.1.11](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policysimulator-v0.1.10...google-cloud-policysimulator-v0.1.11) (2024-12-12) diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py index 558c8aab67c5..17bbab4c1877 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.12" # {x-release-please-version} diff --git a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py index 558c8aab67c5..17bbab4c1877 100644 --- a/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py +++ b/packages/google-cloud-policysimulator/google/cloud/policysimulator_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.12" # {x-release-please-version} diff --git a/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json b/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json index a6025abb1eff..d83ed883debb 100644 --- a/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json +++ b/packages/google-cloud-policysimulator/samples/generated_samples/snippet_metadata_google.cloud.policysimulator.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policysimulator", - "version": "0.1.0" + "version": "0.1.12" }, "snippets": [ { diff --git a/packages/google-cloud-policytroubleshooter-iam/CHANGELOG.md b/packages/google-cloud-policytroubleshooter-iam/CHANGELOG.md index bea4020fcea0..37cdc0e7d77a 100644 --- a/packages/google-cloud-policytroubleshooter-iam/CHANGELOG.md +++ b/packages/google-cloud-policytroubleshooter-iam/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.11](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policytroubleshooter-iam-v0.1.10...google-cloud-policytroubleshooter-iam-v0.1.11) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.1.10](https://github.com/googleapis/google-cloud-python/compare/google-cloud-policytroubleshooter-iam-v0.1.9...google-cloud-policytroubleshooter-iam-v0.1.10) (2024-12-12) diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py index 558c8aab67c5..4b834789ba9e 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.11" # {x-release-please-version} diff --git a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py index 558c8aab67c5..4b834789ba9e 100644 --- a/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py +++ b/packages/google-cloud-policytroubleshooter-iam/google/cloud/policytroubleshooter_iam_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.11" # {x-release-please-version} diff --git a/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json b/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json index 3ec65c7e8d34..b73e4d2b53de 100644 --- a/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json +++ b/packages/google-cloud-policytroubleshooter-iam/samples/generated_samples/snippet_metadata_google.cloud.policytroubleshooter.iam.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-policytroubleshooter-iam", - "version": "0.1.0" + "version": "0.1.11" }, "snippets": [ { diff --git a/packages/google-cloud-private-ca/CHANGELOG.md b/packages/google-cloud-private-ca/CHANGELOG.md index 084ede587f66..b0ab425f06db 100644 --- a/packages/google-cloud-private-ca/CHANGELOG.md +++ b/packages/google-cloud-private-ca/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-ca-v1.14.0...google-cloud-private-ca-v1.14.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-ca-v1.13.1...google-cloud-private-ca-v1.14.0) (2024-12-12) diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py +++ b/packages/google-cloud-private-ca/google/cloud/security/privateca_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json index ca2ab4a8547d..0fcc54a7ac82 100644 --- a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json +++ b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-ca", - "version": "0.1.0" + "version": "1.14.1" }, "snippets": [ { diff --git a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json index a2c343c16a72..14f0b4496bfe 100644 --- a/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json +++ b/packages/google-cloud-private-ca/samples/generated_samples/snippet_metadata_google.cloud.security.privateca.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-ca", - "version": "0.1.0" + "version": "1.14.1" }, "snippets": [ { diff --git a/packages/google-cloud-private-catalog/CHANGELOG.md b/packages/google-cloud-private-catalog/CHANGELOG.md index 0d48722139c7..08d7946cc05c 100644 --- a/packages/google-cloud-private-catalog/CHANGELOG.md +++ b/packages/google-cloud-private-catalog/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.9.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-catalog-v0.9.15...google-cloud-private-catalog-v0.9.16) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.9.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-private-catalog-v0.9.14...google-cloud-private-catalog-v0.9.15) (2025-01-13) diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py index 558c8aab67c5..5d73c1716ca4 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.9.16" # {x-release-please-version} diff --git a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py index 558c8aab67c5..5d73c1716ca4 100644 --- a/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py +++ b/packages/google-cloud-private-catalog/google/cloud/privatecatalog_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.9.16" # {x-release-please-version} diff --git a/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json b/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json index acf623a1683e..7953d90d55d8 100644 --- a/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json +++ b/packages/google-cloud-private-catalog/samples/generated_samples/snippet_metadata_google.cloud.privatecatalog.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-private-catalog", - "version": "0.1.0" + "version": "0.9.16" }, "snippets": [ { diff --git a/packages/google-cloud-privilegedaccessmanager/CHANGELOG.md b/packages/google-cloud-privilegedaccessmanager/CHANGELOG.md index 6ce3ef34aa67..b52f3c2158ad 100644 --- a/packages/google-cloud-privilegedaccessmanager/CHANGELOG.md +++ b/packages/google-cloud-privilegedaccessmanager/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-cloud-privilegedaccessmanager-v0.1.5...google-cloud-privilegedaccessmanager-v0.1.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.1.5](https://github.com/googleapis/google-cloud-python/compare/google-cloud-privilegedaccessmanager-v0.1.4...google-cloud-privilegedaccessmanager-v0.1.5) (2024-12-12) diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py +++ b/packages/google-cloud-privilegedaccessmanager/google/cloud/privilegedaccessmanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json b/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json index ec4443c5cbc9..bf44147a509a 100644 --- a/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json +++ b/packages/google-cloud-privilegedaccessmanager/samples/generated_samples/snippet_metadata_google.cloud.privilegedaccessmanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-privilegedaccessmanager", - "version": "0.1.0" + "version": "0.1.6" }, "snippets": [ { diff --git a/packages/google-cloud-public-ca/CHANGELOG.md b/packages/google-cloud-public-ca/CHANGELOG.md index aba0b4e2f393..3aef17043829 100644 --- a/packages/google-cloud-public-ca/CHANGELOG.md +++ b/packages/google-cloud-public-ca/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.3.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-public-ca-v0.3.15...google-cloud-public-ca-v0.3.16) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.3.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-public-ca-v0.3.14...google-cloud-public-ca-v0.3.15) (2024-12-12) diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py index 558c8aab67c5..f197f80165e7 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.3.16" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py index 558c8aab67c5..f197f80165e7 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.3.16" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py index 558c8aab67c5..f197f80165e7 100644 --- a/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py +++ b/packages/google-cloud-public-ca/google/cloud/security/publicca_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.3.16" # {x-release-please-version} diff --git a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json index 0e5cae8caf1b..c9a07bfeff8d 100644 --- a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json +++ b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-security-publicca", - "version": "0.1.0" + "version": "0.3.16" }, "snippets": [ { diff --git a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json index 5871e5024384..3b999f9d35d4 100644 --- a/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json +++ b/packages/google-cloud-public-ca/samples/generated_samples/snippet_metadata_google.cloud.security.publicca.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-public-ca", - "version": "0.1.0" + "version": "0.3.16" }, "snippets": [ { diff --git a/packages/google-cloud-quotas/CHANGELOG.md b/packages/google-cloud-quotas/CHANGELOG.md index 630507d71945..7f54a57e3cad 100644 --- a/packages/google-cloud-quotas/CHANGELOG.md +++ b/packages/google-cloud-quotas/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-quotas-v0.1.15...google-cloud-quotas-v0.1.16) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.1.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-quotas-v0.1.14...google-cloud-quotas-v0.1.15) (2025-01-13) diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py index 558c8aab67c5..5879ee6ab325 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.16" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py index 558c8aab67c5..5879ee6ab325 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.16" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py index 558c8aab67c5..5879ee6ab325 100644 --- a/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py +++ b/packages/google-cloud-quotas/google/cloud/cloudquotas_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.16" # {x-release-please-version} diff --git a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json index 5c9d0867f7f3..d56dad7c4103 100644 --- a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json +++ b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-quotas", - "version": "0.1.0" + "version": "0.1.16" }, "snippets": [ { diff --git a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json index 785a0e000fa7..640c4051e0f3 100644 --- a/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json +++ b/packages/google-cloud-quotas/samples/generated_samples/snippet_metadata_google.api.cloudquotas.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-quotas", - "version": "0.1.0" + "version": "0.1.16" }, "snippets": [ { diff --git a/packages/google-cloud-rapidmigrationassessment/CHANGELOG.md b/packages/google-cloud-rapidmigrationassessment/CHANGELOG.md index 91f14e61f59c..3cc33fc51039 100644 --- a/packages/google-cloud-rapidmigrationassessment/CHANGELOG.md +++ b/packages/google-cloud-rapidmigrationassessment/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-rapidmigrationassessment-v0.1.12...google-cloud-rapidmigrationassessment-v0.1.13) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-cloud-rapidmigrationassessment-v0.1.11...google-cloud-rapidmigrationassessment-v0.1.12) (2024-12-12) diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py +++ b/packages/google-cloud-rapidmigrationassessment/google/cloud/rapidmigrationassessment_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json b/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json index 2c00dccb6124..15bca09e892b 100644 --- a/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json +++ b/packages/google-cloud-rapidmigrationassessment/samples/generated_samples/snippet_metadata_google.cloud.rapidmigrationassessment.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-rapidmigrationassessment", - "version": "0.1.0" + "version": "0.1.13" }, "snippets": [ { diff --git a/packages/google-cloud-recaptcha-enterprise/CHANGELOG.md b/packages/google-cloud-recaptcha-enterprise/CHANGELOG.md index b3e0326f2e9d..ce8a0639ebb0 100644 --- a/packages/google-cloud-recaptcha-enterprise/CHANGELOG.md +++ b/packages/google-cloud-recaptcha-enterprise/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.27.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recaptcha-enterprise-v1.26.1...google-cloud-recaptcha-enterprise-v1.27.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [1.26.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recaptcha-enterprise-v1.26.0...google-cloud-recaptcha-enterprise-v1.26.1) (2025-01-13) diff --git a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py index 558c8aab67c5..79739e41a21e 100644 --- a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py +++ b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.27.0" # {x-release-please-version} diff --git a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py index 558c8aab67c5..79739e41a21e 100644 --- a/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py +++ b/packages/google-cloud-recaptcha-enterprise/google/cloud/recaptchaenterprise_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.27.0" # {x-release-please-version} diff --git a/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json b/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json index 78c7a5f19cbb..2dc4fcb52e22 100644 --- a/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json +++ b/packages/google-cloud-recaptcha-enterprise/samples/generated_samples/snippet_metadata_google.cloud.recaptchaenterprise.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recaptcha-enterprise", - "version": "0.1.0" + "version": "1.27.0" }, "snippets": [ { diff --git a/packages/google-cloud-recommendations-ai/CHANGELOG.md b/packages/google-cloud-recommendations-ai/CHANGELOG.md index fc95b5ef84e4..3de64af13c5c 100644 --- a/packages/google-cloud-recommendations-ai/CHANGELOG.md +++ b/packages/google-cloud-recommendations-ai/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.10.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommendations-ai-v0.10.15...google-cloud-recommendations-ai-v0.10.16) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.10.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommendations-ai-v0.10.14...google-cloud-recommendations-ai-v0.10.15) (2024-12-12) diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py index 558c8aab67c5..d5275f8b6c39 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.10.16" # {x-release-please-version} diff --git a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py index 558c8aab67c5..d5275f8b6c39 100644 --- a/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py +++ b/packages/google-cloud-recommendations-ai/google/cloud/recommendationengine_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.10.16" # {x-release-please-version} diff --git a/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json b/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json index d22dc88c7d5b..22b730b64e34 100644 --- a/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json +++ b/packages/google-cloud-recommendations-ai/samples/generated_samples/snippet_metadata_google.cloud.recommendationengine.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommendations-ai", - "version": "0.1.0" + "version": "0.10.16" }, "snippets": [ { diff --git a/packages/google-cloud-recommender/CHANGELOG.md b/packages/google-cloud-recommender/CHANGELOG.md index 683b8a7b1cdd..7a3203fa306c 100644 --- a/packages/google-cloud-recommender/CHANGELOG.md +++ b/packages/google-cloud-recommender/CHANGELOG.md @@ -4,6 +4,14 @@ [1]: https://pypi.org/project/google-cloud-recommender/#history +## [2.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommender-v2.17.0...google-cloud-recommender-v2.18.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [2.17.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-recommender-v2.16.1...google-cloud-recommender-v2.17.0) (2024-12-12) diff --git a/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py +++ b/packages/google-cloud-recommender/google/cloud/recommender_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json index 3ccf1bb20a47..4efcb1f749d3 100644 --- a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json +++ b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommender", - "version": "0.1.0" + "version": "2.18.0" }, "snippets": [ { diff --git a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json index 01d4bcaa2c08..955eaa5e2d74 100644 --- a/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json +++ b/packages/google-cloud-recommender/samples/generated_samples/snippet_metadata_google.cloud.recommender.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-recommender", - "version": "0.1.0" + "version": "2.18.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis-cluster/CHANGELOG.md b/packages/google-cloud-redis-cluster/CHANGELOG.md index 7a2c2eeec5f4..52af286a1515 100644 --- a/packages/google-cloud-redis-cluster/CHANGELOG.md +++ b/packages/google-cloud-redis-cluster/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-cluster-v0.1.13...google-cloud-redis-cluster-v0.1.14) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-cluster-v0.1.12...google-cloud-redis-cluster-v0.1.13) (2025-01-20) diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py index 558c8aab67c5..7a4d810a47da 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.14" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py index 558c8aab67c5..7a4d810a47da 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.14" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py index 558c8aab67c5..7a4d810a47da 100644 --- a/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py +++ b/packages/google-cloud-redis-cluster/google/cloud/redis_cluster_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.14" # {x-release-please-version} diff --git a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json index 9713cf9d56ac..43668aabb0ba 100644 --- a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json +++ b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis-cluster", - "version": "0.1.0" + "version": "0.1.14" }, "snippets": [ { diff --git a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json index 3512a9cf90ac..ac07a8985dc7 100644 --- a/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json +++ b/packages/google-cloud-redis-cluster/samples/generated_samples/snippet_metadata_google.cloud.redis.cluster.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis-cluster", - "version": "0.1.0" + "version": "0.1.14" }, "snippets": [ { diff --git a/packages/google-cloud-redis/CHANGELOG.md b/packages/google-cloud-redis/CHANGELOG.md index b4033f56fd5b..60e098cabd29 100644 --- a/packages/google-cloud-redis/CHANGELOG.md +++ b/packages/google-cloud-redis/CHANGELOG.md @@ -4,6 +4,14 @@ [1]: https://pypi.org/project/google-cloud-redis/#history +## [2.18.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-v2.17.0...google-cloud-redis-v2.18.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [2.17.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-redis-v2.16.1...google-cloud-redis-v2.17.0) (2024-12-12) diff --git a/packages/google-cloud-redis/google/cloud/redis/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-redis/google/cloud/redis/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py b/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py index 558c8aab67c5..1074c4de1723 100644 --- a/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py +++ b/packages/google-cloud-redis/google/cloud/redis_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.18.0" # {x-release-please-version} diff --git a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json index 78f872bc4aef..91a515d0fcf7 100644 --- a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json +++ b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis", - "version": "0.1.0" + "version": "2.18.0" }, "snippets": [ { diff --git a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json index e1412dd446e5..40506c428f5b 100644 --- a/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json +++ b/packages/google-cloud-redis/samples/generated_samples/snippet_metadata_google.cloud.redis.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-redis", - "version": "0.1.0" + "version": "2.18.0" }, "snippets": [ { diff --git a/packages/google-cloud-resource-manager/CHANGELOG.md b/packages/google-cloud-resource-manager/CHANGELOG.md index 1efc1828a6ba..05a38e3c3015 100644 --- a/packages/google-cloud-resource-manager/CHANGELOG.md +++ b/packages/google-cloud-resource-manager/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-resource-manager/#history +## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-manager-v1.14.0...google-cloud-resource-manager-v1.14.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-manager-v1.13.1...google-cloud-resource-manager-v1.14.0) (2024-12-12) diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py +++ b/packages/google-cloud-resource-manager/google/cloud/resourcemanager_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json b/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json index 18bac0c91496..bb9124deb6b0 100644 --- a/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json +++ b/packages/google-cloud-resource-manager/samples/generated_samples/snippet_metadata_google.cloud.resourcemanager.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-resource-manager", - "version": "0.1.0" + "version": "1.14.1" }, "snippets": [ { diff --git a/packages/google-cloud-resource-settings/CHANGELOG.md b/packages/google-cloud-resource-settings/CHANGELOG.md index 79cf39b5216f..b87a60a69aad 100644 --- a/packages/google-cloud-resource-settings/CHANGELOG.md +++ b/packages/google-cloud-resource-settings/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.12.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-settings-v1.11.0...google-cloud-resource-settings-v1.12.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [1.11.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-resource-settings-v1.10.1...google-cloud-resource-settings-v1.11.0) (2024-12-12) diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py index 558c8aab67c5..739fdfae141c 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.12.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py index 558c8aab67c5..739fdfae141c 100644 --- a/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py +++ b/packages/google-cloud-resource-settings/google/cloud/resourcesettings_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.12.0" # {x-release-please-version} diff --git a/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json b/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json index 61a2b1d93fba..e602381cb824 100644 --- a/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json +++ b/packages/google-cloud-resource-settings/samples/generated_samples/snippet_metadata_google.cloud.resourcesettings.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-resource-settings", - "version": "0.1.0" + "version": "1.12.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/CHANGELOG.md b/packages/google-cloud-retail/CHANGELOG.md index e8af8bd738ee..897c2c9c1d1d 100644 --- a/packages/google-cloud-retail/CHANGELOG.md +++ b/packages/google-cloud-retail/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.25.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-retail-v1.24.0...google-cloud-retail-v1.25.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [1.24.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-retail-v1.23.1...google-cloud-retail-v1.24.0) (2024-12-12) diff --git a/packages/google-cloud-retail/google/cloud/retail/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail/gapic_version.py index 558c8aab67c5..547a38985bb7 100644 --- a/packages/google-cloud-retail/google/cloud/retail/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py index 558c8aab67c5..547a38985bb7 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py index 558c8aab67c5..547a38985bb7 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2alpha/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py b/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py index 558c8aab67c5..547a38985bb7 100644 --- a/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py +++ b/packages/google-cloud-retail/google/cloud/retail_v2beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.25.0" # {x-release-please-version} diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json index 2551a0da71ff..a19e5027177c 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "0.1.0" + "version": "1.25.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json index b27771e5b373..a6e8e2741a76 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2alpha.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "0.1.0" + "version": "1.25.0" }, "snippets": [ { diff --git a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json index 5b91d0f376d7..17843a848257 100644 --- a/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json +++ b/packages/google-cloud-retail/samples/generated_samples/snippet_metadata_google.cloud.retail.v2beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-retail", - "version": "0.1.0" + "version": "1.25.0" }, "snippets": [ { diff --git a/packages/google-cloud-run/CHANGELOG.md b/packages/google-cloud-run/CHANGELOG.md index c27bc4fac3e0..f67551952ad7 100644 --- a/packages/google-cloud-run/CHANGELOG.md +++ b/packages/google-cloud-run/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog +## [0.10.16](https://github.com/googleapis/google-cloud-python/compare/google-cloud-run-v0.10.15...google-cloud-run-v0.10.16) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.10.15](https://github.com/googleapis/google-cloud-python/compare/google-cloud-run-v0.10.14...google-cloud-run-v0.10.15) (2025-02-12) diff --git a/packages/google-cloud-run/google/cloud/run/gapic_version.py b/packages/google-cloud-run/google/cloud/run/gapic_version.py index 558c8aab67c5..d5275f8b6c39 100644 --- a/packages/google-cloud-run/google/cloud/run/gapic_version.py +++ b/packages/google-cloud-run/google/cloud/run/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.10.16" # {x-release-please-version} diff --git a/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py b/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py index 558c8aab67c5..d5275f8b6c39 100644 --- a/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py +++ b/packages/google-cloud-run/google/cloud/run_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.10.16" # {x-release-please-version} diff --git a/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json b/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json index 91a10655bff1..e0d127a8803c 100644 --- a/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json +++ b/packages/google-cloud-run/samples/generated_samples/snippet_metadata_google.cloud.run.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-run", - "version": "0.1.0" + "version": "0.10.16" }, "snippets": [ { diff --git a/packages/google-cloud-scheduler/CHANGELOG.md b/packages/google-cloud-scheduler/CHANGELOG.md index 26bae0199cb2..ab2b44ec2d47 100644 --- a/packages/google-cloud-scheduler/CHANGELOG.md +++ b/packages/google-cloud-scheduler/CHANGELOG.md @@ -4,6 +4,14 @@ [1]: https://pypi.org/project/google-cloud-scheduler/#history +## [2.16.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-scheduler-v2.15.1...google-cloud-scheduler-v2.16.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) +* Add support for reading selective GAPIC generation methods from service YAML ([c8e0760](https://github.com/googleapis/google-cloud-python/commit/c8e0760e8088950c62279335216ad1d17716ce59)) + ## [2.15.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-scheduler-v2.15.0...google-cloud-scheduler-v2.15.1) (2025-01-27) diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py index 558c8aab67c5..e154065d8da8 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.16.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py index 558c8aab67c5..e154065d8da8 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.16.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py index 558c8aab67c5..e154065d8da8 100644 --- a/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py +++ b/packages/google-cloud-scheduler/google/cloud/scheduler_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.16.0" # {x-release-please-version} diff --git a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json index 150f660ac6a2..f3786a00b383 100644 --- a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json +++ b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-scheduler", - "version": "0.1.0" + "version": "2.16.0" }, "snippets": [ { diff --git a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json index 579bee0411e1..fe7bab65181a 100644 --- a/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json +++ b/packages/google-cloud-scheduler/samples/generated_samples/snippet_metadata_google.cloud.scheduler.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-scheduler", - "version": "0.1.0" + "version": "2.16.0" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/CHANGELOG.md b/packages/google-cloud-secret-manager/CHANGELOG.md index 68567a40ca8d..a3584fad06ad 100644 --- a/packages/google-cloud-secret-manager/CHANGELOG.md +++ b/packages/google-cloud-secret-manager/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.23.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-secret-manager-v2.23.0...google-cloud-secret-manager-v2.23.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [2.23.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-secret-manager-v2.22.1...google-cloud-secret-manager-v2.23.0) (2025-02-12) diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py index 558c8aab67c5..64dfd834b468 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py index 558c8aab67c5..64dfd834b468 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py index 558c8aab67c5..64dfd834b468 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py index 558c8aab67c5..64dfd834b468 100644 --- a/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py +++ b/packages/google-cloud-secret-manager/google/cloud/secretmanager_v1beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.23.1" # {x-release-please-version} diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json index e75ffe273c93..1152533a2dad 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secret-manager", - "version": "0.1.0" + "version": "2.23.1" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json index f2d2a2eaea8e..7e4886ca3e5a 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secretmanager.v1beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secretmanager", - "version": "0.1.0" + "version": "2.23.1" }, "snippets": [ { diff --git a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json index cdba6a34a0ba..727d169b2520 100644 --- a/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json +++ b/packages/google-cloud-secret-manager/samples/generated_samples/snippet_metadata_google.cloud.secrets.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-secretmanager", - "version": "0.1.0" + "version": "2.23.1" }, "snippets": [ { diff --git a/packages/google-cloud-securesourcemanager/CHANGELOG.md b/packages/google-cloud-securesourcemanager/CHANGELOG.md index 2febe4c9028f..ad4932d09141 100644 --- a/packages/google-cloud-securesourcemanager/CHANGELOG.md +++ b/packages/google-cloud-securesourcemanager/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.14](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securesourcemanager-v0.1.13...google-cloud-securesourcemanager-v0.1.14) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securesourcemanager-v0.1.12...google-cloud-securesourcemanager-v0.1.13) (2025-02-12) diff --git a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py index 558c8aab67c5..7a4d810a47da 100644 --- a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py +++ b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.14" # {x-release-please-version} diff --git a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py index 558c8aab67c5..7a4d810a47da 100644 --- a/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py +++ b/packages/google-cloud-securesourcemanager/google/cloud/securesourcemanager_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.14" # {x-release-please-version} diff --git a/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json b/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json index 61b28fdc2e03..f5b79bc1157a 100644 --- a/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json +++ b/packages/google-cloud-securesourcemanager/samples/generated_samples/snippet_metadata_google.cloud.securesourcemanager.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securesourcemanager", - "version": "0.1.0" + "version": "0.1.14" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/CHANGELOG.md b/packages/google-cloud-securitycenter/CHANGELOG.md index 11334a368bde..e67b0fbbd951 100644 --- a/packages/google-cloud-securitycenter/CHANGELOG.md +++ b/packages/google-cloud-securitycenter/CHANGELOG.md @@ -4,6 +4,24 @@ [1]: https://pypi.org/project/google-cloud-securitycenter/#history +## [1.38.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycenter-v1.37.0...google-cloud-securitycenter-v1.38.0) (2025-02-18) + + +### Features + +* added data access event fields to finding proto ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b)) +* added more information about DDoS attack in cloud armor proto ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b)) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + + +### Documentation + +* Clarified comments for tag_values field in resource_value_config to make it clear that field represents tag value ids, not tag values ([7fb3f49](https://github.com/googleapis/google-cloud-python/commit/7fb3f49a1531b4da24771c4ce8380be98980fe8b)) + ## [1.37.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycenter-v1.36.0...google-cloud-securitycenter-v1.37.0) (2025-02-12) diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py index 558c8aab67c5..e553ae451f41 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.38.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py index 558c8aab67c5..e553ae451f41 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.38.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py index 558c8aab67c5..e553ae451f41 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.38.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py index 558c8aab67c5..e553ae451f41 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v1p1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.38.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py index 558c8aab67c5..e553ae451f41 100644 --- a/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py +++ b/packages/google-cloud-securitycenter/google/cloud/securitycenter_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.38.0" # {x-release-please-version} diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json index efb11fe5de6c..66674c8fe37d 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "0.1.0" + "version": "1.38.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json index dc6a6d6dd78d..32f339fb0691 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "0.1.0" + "version": "1.38.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json index 7eed8e8dc8ab..9e8b8a426974 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "0.1.0" + "version": "1.38.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json index e176e0b8c043..3429bc3115f4 100644 --- a/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json +++ b/packages/google-cloud-securitycenter/samples/generated_samples/snippet_metadata_google.cloud.securitycenter.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycenter", - "version": "0.1.0" + "version": "1.38.0" }, "snippets": [ { diff --git a/packages/google-cloud-securitycentermanagement/CHANGELOG.md b/packages/google-cloud-securitycentermanagement/CHANGELOG.md index 74362ddf2b96..33b714263d9c 100644 --- a/packages/google-cloud-securitycentermanagement/CHANGELOG.md +++ b/packages/google-cloud-securitycentermanagement/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.20](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycentermanagement-v0.1.19...google-cloud-securitycentermanagement-v0.1.20) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.1.19](https://github.com/googleapis/google-cloud-python/compare/google-cloud-securitycentermanagement-v0.1.18...google-cloud-securitycentermanagement-v0.1.19) (2025-02-12) diff --git a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py index 558c8aab67c5..e04ba333d337 100644 --- a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py +++ b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.20" # {x-release-please-version} diff --git a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py index 558c8aab67c5..e04ba333d337 100644 --- a/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py +++ b/packages/google-cloud-securitycentermanagement/google/cloud/securitycentermanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.20" # {x-release-please-version} diff --git a/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json b/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json index aa268d46e53c..f4790fa63171 100644 --- a/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json +++ b/packages/google-cloud-securitycentermanagement/samples/generated_samples/snippet_metadata_google.cloud.securitycentermanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-securitycentermanagement", - "version": "0.1.0" + "version": "0.1.20" }, "snippets": [ { diff --git a/packages/google-cloud-service-directory/CHANGELOG.md b/packages/google-cloud-service-directory/CHANGELOG.md index 137e7e0e4fb9..e9238b94d537 100644 --- a/packages/google-cloud-service-directory/CHANGELOG.md +++ b/packages/google-cloud-service-directory/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.14.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-directory-v1.14.0...google-cloud-service-directory-v1.14.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-directory-v1.13.0...google-cloud-service-directory-v1.14.0) (2025-02-12) diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py index 558c8aab67c5..231f5cf041ff 100644 --- a/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py +++ b/packages/google-cloud-service-directory/google/cloud/servicedirectory_v1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.1" # {x-release-please-version} diff --git a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json index bb916a8e137a..29b23ef45493 100644 --- a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json +++ b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-directory", - "version": "0.1.0" + "version": "1.14.1" }, "snippets": [ { diff --git a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json index bbc7749e9905..c9132280f70e 100644 --- a/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json +++ b/packages/google-cloud-service-directory/samples/generated_samples/snippet_metadata_google.cloud.servicedirectory.v1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-directory", - "version": "0.1.0" + "version": "1.14.1" }, "snippets": [ { diff --git a/packages/google-cloud-service-management/CHANGELOG.md b/packages/google-cloud-service-management/CHANGELOG.md index 9fcc1c33b888..277f6a1d5676 100644 --- a/packages/google-cloud-service-management/CHANGELOG.md +++ b/packages/google-cloud-service-management/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-management-v1.13.0...google-cloud-service-management-v1.13.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-service-management-v1.12.0...google-cloud-service-management-v1.13.0) (2025-02-12) diff --git a/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py b/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py +++ b/packages/google-cloud-service-management/google/cloud/servicemanagement/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py b/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py index 558c8aab67c5..0b9427f4e8a5 100644 --- a/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py +++ b/packages/google-cloud-service-management/google/cloud/servicemanagement_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.13.1" # {x-release-please-version} diff --git a/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json b/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json index fb37827cecec..f689a0c954d1 100644 --- a/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json +++ b/packages/google-cloud-service-management/samples/generated_samples/snippet_metadata_google.api.servicemanagement.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-service-management", - "version": "0.1.0" + "version": "1.13.1" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/CHANGELOG.md b/packages/google-cloud-tasks/CHANGELOG.md index 1055b7e18127..ed148717ecdb 100644 --- a/packages/google-cloud-tasks/CHANGELOG.md +++ b/packages/google-cloud-tasks/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-tasks/#history +## [2.19.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-tasks-v2.19.0...google-cloud-tasks-v2.19.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [2.19.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-tasks-v2.18.0...google-cloud-tasks-v2.19.0) (2025-02-12) diff --git a/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py index 558c8aab67c5..25b64b58a421 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.19.1" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py index 558c8aab67c5..25b64b58a421 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.19.1" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py index 558c8aab67c5..25b64b58a421 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2beta2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.19.1" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py b/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py index 558c8aab67c5..25b64b58a421 100644 --- a/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py +++ b/packages/google-cloud-tasks/google/cloud/tasks_v2beta3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "2.19.1" # {x-release-please-version} diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json index a40f846fdcce..da0b2077dbd4 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "0.1.0" + "version": "2.19.1" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json index 2b3fcc2324d1..b4e327ba61f8 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "0.1.0" + "version": "2.19.1" }, "snippets": [ { diff --git a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json index c3812fadd698..eb16d5bf2576 100644 --- a/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json +++ b/packages/google-cloud-tasks/samples/generated_samples/snippet_metadata_google.cloud.tasks.v2beta3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-tasks", - "version": "0.1.0" + "version": "2.19.1" }, "snippets": [ { diff --git a/packages/google-cloud-translate/CHANGELOG.md b/packages/google-cloud-translate/CHANGELOG.md index de3766c9e9ea..178b5b01888b 100644 --- a/packages/google-cloud-translate/CHANGELOG.md +++ b/packages/google-cloud-translate/CHANGELOG.md @@ -5,6 +5,13 @@ [1]: https://pypi.org/project/google-cloud-translate/#history +## [3.20.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-translate-v3.20.0...google-cloud-translate-v3.20.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [3.20.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-translate-v3.19.0...google-cloud-translate-v3.20.0) (2025-02-12) diff --git a/packages/google-cloud-translate/google/cloud/translate/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate/gapic_version.py index 558c8aab67c5..91a01ec63c59 100644 --- a/packages/google-cloud-translate/google/cloud/translate/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py index 558c8aab67c5..91a01ec63c59 100644 --- a/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py b/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py index 558c8aab67c5..91a01ec63c59 100644 --- a/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py +++ b/packages/google-cloud-translate/google/cloud/translate_v3beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "3.20.1" # {x-release-please-version} diff --git a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json index de406536e428..f1a519a164b5 100644 --- a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json +++ b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-translate", - "version": "0.1.0" + "version": "3.20.1" }, "snippets": [ { diff --git a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json index 74f2e4c9def9..d0c05cc83682 100644 --- a/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json +++ b/packages/google-cloud-translate/samples/generated_samples/snippet_metadata_google.cloud.translation.v3beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-translate", - "version": "0.1.0" + "version": "3.20.1" }, "snippets": [ { diff --git a/packages/google-cloud-visionai/CHANGELOG.md b/packages/google-cloud-visionai/CHANGELOG.md index fb434cce8961..fa90085e16fc 100644 --- a/packages/google-cloud-visionai/CHANGELOG.md +++ b/packages/google-cloud-visionai/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-cloud-visionai-v0.1.7...google-cloud-visionai-v0.1.8) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([770cf0f](https://github.com/googleapis/google-cloud-python/commit/770cf0f31125586a8622e9639f6d24c1bafa9b31)) + ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-cloud-visionai-v0.1.6...google-cloud-visionai-v0.1.7) (2025-02-12) diff --git a/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py b/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py +++ b/packages/google-cloud-visionai/google/cloud/visionai_v1alpha1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json index 55144efe90c6..ae6746cc0455 100644 --- a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json +++ b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-visionai", - "version": "0.1.0" + "version": "0.1.8" }, "snippets": [ { diff --git a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json index 11704c120259..e8088492fb3c 100644 --- a/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json +++ b/packages/google-cloud-visionai/samples/generated_samples/snippet_metadata_google.cloud.visionai.v1alpha1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-visionai", - "version": "0.1.0" + "version": "0.1.8" }, "snippets": [ { diff --git a/packages/google-cloud-vm-migration/CHANGELOG.md b/packages/google-cloud-vm-migration/CHANGELOG.md index 1c376a7505e0..d8ac4bf66f46 100644 --- a/packages/google-cloud-vm-migration/CHANGELOG.md +++ b/packages/google-cloud-vm-migration/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.11.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vm-migration-v1.11.0...google-cloud-vm-migration-v1.11.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8)) + ## [1.11.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vm-migration-v1.10.0...google-cloud-vm-migration-v1.11.0) (2025-02-12) diff --git a/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py b/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py index 558c8aab67c5..b50cada0b7ee 100644 --- a/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py +++ b/packages/google-cloud-vm-migration/google/cloud/vmmigration/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.11.1" # {x-release-please-version} diff --git a/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py b/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py index 558c8aab67c5..b50cada0b7ee 100644 --- a/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py +++ b/packages/google-cloud-vm-migration/google/cloud/vmmigration_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.11.1" # {x-release-please-version} diff --git a/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json b/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json index cfb6d660b704..a209cb6e6b4b 100644 --- a/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json +++ b/packages/google-cloud-vm-migration/samples/generated_samples/snippet_metadata_google.cloud.vmmigration.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-vm-migration", - "version": "0.1.0" + "version": "1.11.1" }, "snippets": [ { diff --git a/packages/google-cloud-vmwareengine/CHANGELOG.md b/packages/google-cloud-vmwareengine/CHANGELOG.md index 15c41a21733a..3ce72054cef9 100644 --- a/packages/google-cloud-vmwareengine/CHANGELOG.md +++ b/packages/google-cloud-vmwareengine/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.8.1](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vmwareengine-v1.8.0...google-cloud-vmwareengine-v1.8.1) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8)) + ## [1.8.0](https://github.com/googleapis/google-cloud-python/compare/google-cloud-vmwareengine-v1.7.0...google-cloud-vmwareengine-v1.8.0) (2025-02-12) diff --git a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py index 558c8aab67c5..02874f69f4e5 100644 --- a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py +++ b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.8.1" # {x-release-please-version} diff --git a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py index 558c8aab67c5..02874f69f4e5 100644 --- a/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py +++ b/packages/google-cloud-vmwareengine/google/cloud/vmwareengine_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.8.1" # {x-release-please-version} diff --git a/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json b/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json index 6d234586a410..ba05a0122b87 100644 --- a/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json +++ b/packages/google-cloud-vmwareengine/samples/generated_samples/snippet_metadata_google.cloud.vmwareengine.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-vmwareengine", - "version": "0.1.0" + "version": "1.8.1" }, "snippets": [ { diff --git a/packages/google-cloud-workstations/CHANGELOG.md b/packages/google-cloud-workstations/CHANGELOG.md index 926046bd1713..f8b7816b532f 100644 --- a/packages/google-cloud-workstations/CHANGELOG.md +++ b/packages/google-cloud-workstations/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.13](https://github.com/googleapis/google-cloud-python/compare/google-cloud-workstations-v0.5.12...google-cloud-workstations-v0.5.13) (2025-02-18) + + +### Bug Fixes + +* **deps:** Require grpc-google-iam-v1>=0.14.0 ([0c5f868](https://github.com/googleapis/google-cloud-python/commit/0c5f86820c42e5cd857c1a0eef25f5e6a65b2ad8)) + ## [0.5.12](https://github.com/googleapis/google-cloud-python/compare/google-cloud-workstations-v0.5.11...google-cloud-workstations-v0.5.12) (2025-02-12) diff --git a/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py index 558c8aab67c5..bf678492aaad 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.13" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py index 558c8aab67c5..bf678492aaad 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.13" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py index 558c8aab67c5..bf678492aaad 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.5.13" # {x-release-please-version} diff --git a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json index c9f644c1d20c..7b9e727ebead 100644 --- a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json +++ b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-workstations", - "version": "0.1.0" + "version": "0.5.13" }, "snippets": [ { diff --git a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json index 2a6523f2cb2d..945be6c103a9 100644 --- a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json +++ b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-workstations", - "version": "0.1.0" + "version": "0.5.13" }, "snippets": [ { diff --git a/packages/google-maps-mapsplatformdatasets/CHANGELOG.md b/packages/google-maps-mapsplatformdatasets/CHANGELOG.md index 26ea1f8791e8..dbe73caa5864 100644 --- a/packages/google-maps-mapsplatformdatasets/CHANGELOG.md +++ b/packages/google-maps-mapsplatformdatasets/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.4.6](https://github.com/googleapis/google-cloud-python/compare/google-maps-mapsplatformdatasets-v0.4.5...google-maps-mapsplatformdatasets-v0.4.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.4.5](https://github.com/googleapis/google-cloud-python/compare/google-maps-mapsplatformdatasets-v0.4.4...google-maps-mapsplatformdatasets-v0.4.5) (2024-12-12) diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py index 558c8aab67c5..dbe5d0a1aca6 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.6" # {x-release-please-version} diff --git a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py index 558c8aab67c5..dbe5d0a1aca6 100644 --- a/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py +++ b/packages/google-maps-mapsplatformdatasets/google/maps/mapsplatformdatasets_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.4.6" # {x-release-please-version} diff --git a/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json b/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json index efd05ec97721..6d968b93490a 100644 --- a/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json +++ b/packages/google-maps-mapsplatformdatasets/samples/generated_samples/snippet_metadata_google.maps.mapsplatformdatasets.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-mapsplatformdatasets", - "version": "0.1.0" + "version": "0.4.6" }, "snippets": [ { diff --git a/packages/google-maps-routeoptimization/CHANGELOG.md b/packages/google-maps-routeoptimization/CHANGELOG.md index c48c41aa516d..51bddde0cbc0 100644 --- a/packages/google-maps-routeoptimization/CHANGELOG.md +++ b/packages/google-maps-routeoptimization/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-maps-routeoptimization-v0.1.7...google-maps-routeoptimization-v0.1.8) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-maps-routeoptimization-v0.1.6...google-maps-routeoptimization-v0.1.7) (2024-12-12) diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py +++ b/packages/google-maps-routeoptimization/google/maps/routeoptimization_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json b/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json index fcfcf65d2f4f..175ac7006bd9 100644 --- a/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json +++ b/packages/google-maps-routeoptimization/samples/generated_samples/snippet_metadata_google.maps.routeoptimization.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-routeoptimization", - "version": "0.1.0" + "version": "0.1.8" }, "snippets": [ { diff --git a/packages/google-maps-routing/CHANGELOG.md b/packages/google-maps-routing/CHANGELOG.md index 041d1e74e38a..cc5238e3e716 100644 --- a/packages/google-maps-routing/CHANGELOG.md +++ b/packages/google-maps-routing/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.6.14](https://github.com/googleapis/google-cloud-python/compare/google-maps-routing-v0.6.13...google-maps-routing-v0.6.14) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.6.13](https://github.com/googleapis/google-cloud-python/compare/google-maps-routing-v0.6.12...google-maps-routing-v0.6.13) (2024-12-12) diff --git a/packages/google-maps-routing/google/maps/routing/gapic_version.py b/packages/google-maps-routing/google/maps/routing/gapic_version.py index 558c8aab67c5..0b6dbde2b051 100644 --- a/packages/google-maps-routing/google/maps/routing/gapic_version.py +++ b/packages/google-maps-routing/google/maps/routing/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.14" # {x-release-please-version} diff --git a/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py b/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py index 558c8aab67c5..0b6dbde2b051 100644 --- a/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py +++ b/packages/google-maps-routing/google/maps/routing_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.6.14" # {x-release-please-version} diff --git a/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json b/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json index ebb0fa3e0c00..3acf0b4b8ff9 100644 --- a/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json +++ b/packages/google-maps-routing/samples/generated_samples/snippet_metadata_google.maps.routing.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-routing", - "version": "0.1.0" + "version": "0.6.14" }, "snippets": [ { diff --git a/packages/google-maps-solar/CHANGELOG.md b/packages/google-maps-solar/CHANGELOG.md index f2cffc0184ba..6caba62d93ac 100644 --- a/packages/google-maps-solar/CHANGELOG.md +++ b/packages/google-maps-solar/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-maps-solar-v0.1.5...google-maps-solar-v0.1.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.5](https://github.com/googleapis/google-cloud-python/compare/google-maps-solar-v0.1.4...google-maps-solar-v0.1.5) (2024-12-12) diff --git a/packages/google-maps-solar/google/maps/solar/gapic_version.py b/packages/google-maps-solar/google/maps/solar/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-maps-solar/google/maps/solar/gapic_version.py +++ b/packages/google-maps-solar/google/maps/solar/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py b/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py +++ b/packages/google-maps-solar/google/maps/solar_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json b/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json index b0cd14fdb324..c7248c463bbe 100644 --- a/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json +++ b/packages/google-maps-solar/samples/generated_samples/snippet_metadata_google.maps.solar.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-maps-solar", - "version": "0.1.0" + "version": "0.1.6" }, "snippets": [ { diff --git a/packages/google-shopping-css/CHANGELOG.md b/packages/google-shopping-css/CHANGELOG.md index 807ac56bf1de..9b2b8599975a 100644 --- a/packages/google-shopping-css/CHANGELOG.md +++ b/packages/google-shopping-css/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-css-v0.1.12...google-shopping-css-v0.1.13) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-shopping-css-v0.1.11...google-shopping-css-v0.1.12) (2025-01-02) diff --git a/packages/google-shopping-css/google/shopping/css/gapic_version.py b/packages/google-shopping-css/google/shopping/css/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-css/google/shopping/css/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json index 6cbd0ab66db5..cf47cbaa7363 100644 --- a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json +++ b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-css", - "version": "0.1.0" + "version": "0.1.13" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-accounts/CHANGELOG.md b/packages/google-shopping-merchant-accounts/CHANGELOG.md index 8ac10aafa7ed..0918695dcb62 100644 --- a/packages/google-shopping-merchant-accounts/CHANGELOG.md +++ b/packages/google-shopping-merchant-accounts/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.2.4](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-accounts-v0.2.3...google-shopping-merchant-accounts-v0.2.4) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.2.3](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-accounts-v0.2.2...google-shopping-merchant-accounts-v0.2.3) (2024-12-12) diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py index 558c8aab67c5..668eac0d72ce 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.4" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py index 558c8aab67c5..668eac0d72ce 100644 --- a/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-accounts/google/shopping/merchant_accounts_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.4" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json b/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json index c736f9d3c831..d16daac3e932 100644 --- a/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json +++ b/packages/google-shopping-merchant-accounts/samples/generated_samples/snippet_metadata_google.shopping.merchant.accounts.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-accounts", - "version": "0.1.0" + "version": "0.2.4" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-conversions/CHANGELOG.md b/packages/google-shopping-merchant-conversions/CHANGELOG.md index 561d3f9679f6..55fce332a9c3 100644 --- a/packages/google-shopping-merchant-conversions/CHANGELOG.md +++ b/packages/google-shopping-merchant-conversions/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-conversions-v0.1.6...google-shopping-merchant-conversions-v0.1.7) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-conversions-v0.1.5...google-shopping-merchant-conversions-v0.1.6) (2024-12-12) diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-conversions/google/shopping/merchant_conversions_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json b/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json index 7b979a5c445b..14d739eb3900 100644 --- a/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json +++ b/packages/google-shopping-merchant-conversions/samples/generated_samples/snippet_metadata_google.shopping.merchant.conversions.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-conversions", - "version": "0.1.0" + "version": "0.1.7" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-datasources/CHANGELOG.md b/packages/google-shopping-merchant-datasources/CHANGELOG.md index d8ce7ce383d0..f2aa82cdfa48 100644 --- a/packages/google-shopping-merchant-datasources/CHANGELOG.md +++ b/packages/google-shopping-merchant-datasources/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.8](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-datasources-v0.1.7...google-shopping-merchant-datasources-v0.1.8) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-datasources-v0.1.6...google-shopping-merchant-datasources-v0.1.7) (2025-01-13) diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py index 558c8aab67c5..ec8d212c9160 100644 --- a/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-datasources/google/shopping/merchant_datasources_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.8" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json b/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json index 992de0dc6fb0..151340a3118e 100644 --- a/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json +++ b/packages/google-shopping-merchant-datasources/samples/generated_samples/snippet_metadata_google.shopping.merchant.datasources.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-datasources", - "version": "0.1.0" + "version": "0.1.8" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-inventories/CHANGELOG.md b/packages/google-shopping-merchant-inventories/CHANGELOG.md index 99f3bd545904..2a28d5747b65 100644 --- a/packages/google-shopping-merchant-inventories/CHANGELOG.md +++ b/packages/google-shopping-merchant-inventories/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-inventories-v0.1.12...google-shopping-merchant-inventories-v0.1.13) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-inventories-v0.1.11...google-shopping-merchant-inventories-v0.1.12) (2024-12-12) diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-inventories/google/shopping/merchant_inventories_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json b/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json index 73ddfcf94070..52156a687aa3 100644 --- a/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json +++ b/packages/google-shopping-merchant-inventories/samples/generated_samples/snippet_metadata_google.shopping.merchant.inventories.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-inventories", - "version": "0.1.0" + "version": "0.1.13" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-lfp/CHANGELOG.md b/packages/google-shopping-merchant-lfp/CHANGELOG.md index 2e42fb94b984..9aeb7d4bb48f 100644 --- a/packages/google-shopping-merchant-lfp/CHANGELOG.md +++ b/packages/google-shopping-merchant-lfp/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.7](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-lfp-v0.1.6...google-shopping-merchant-lfp-v0.1.7) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-lfp-v0.1.5...google-shopping-merchant-lfp-v0.1.6) (2024-12-12) diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py index 558c8aab67c5..cf5493b86bbc 100644 --- a/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-lfp/google/shopping/merchant_lfp_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.7" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json b/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json index c88051dded42..b28332e40d38 100644 --- a/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json +++ b/packages/google-shopping-merchant-lfp/samples/generated_samples/snippet_metadata_google.shopping.merchant.lfp.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-lfp", - "version": "0.1.0" + "version": "0.1.7" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-notifications/CHANGELOG.md b/packages/google-shopping-merchant-notifications/CHANGELOG.md index 432878375518..332da479e42e 100644 --- a/packages/google-shopping-merchant-notifications/CHANGELOG.md +++ b/packages/google-shopping-merchant-notifications/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-notifications-v0.1.5...google-shopping-merchant-notifications-v0.1.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.5](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-notifications-v0.1.4...google-shopping-merchant-notifications-v0.1.5) (2024-12-12) diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-notifications/google/shopping/merchant_notifications_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json b/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json index b27b3eb2144a..ae836dc4a086 100644 --- a/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json +++ b/packages/google-shopping-merchant-notifications/samples/generated_samples/snippet_metadata_google.shopping.merchant.notifications.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-notifications", - "version": "0.1.0" + "version": "0.1.6" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-products/CHANGELOG.md b/packages/google-shopping-merchant-products/CHANGELOG.md index 55d6398cdc04..1bd353c1e4a3 100644 --- a/packages/google-shopping-merchant-products/CHANGELOG.md +++ b/packages/google-shopping-merchant-products/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.2.1](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-products-v0.2.0...google-shopping-merchant-products-v0.2.1) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.2.0](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-products-v0.1.4...google-shopping-merchant-products-v0.2.0) (2024-12-12) diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py index 558c8aab67c5..6d8247638d59 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.1" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py index 558c8aab67c5..6d8247638d59 100644 --- a/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-products/google/shopping/merchant_products_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.2.1" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json b/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json index c50174f47a66..92b598a71b68 100644 --- a/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json +++ b/packages/google-shopping-merchant-products/samples/generated_samples/snippet_metadata_google.shopping.merchant.products.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-products", - "version": "0.1.0" + "version": "0.2.1" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-promotions/CHANGELOG.md b/packages/google-shopping-merchant-promotions/CHANGELOG.md index 3b52d00440e0..aa3889457d3a 100644 --- a/packages/google-shopping-merchant-promotions/CHANGELOG.md +++ b/packages/google-shopping-merchant-promotions/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-promotions-v0.1.5...google-shopping-merchant-promotions-v0.1.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.5](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-promotions-v0.1.4...google-shopping-merchant-promotions-v0.1.5) (2024-12-12) diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-promotions/google/shopping/merchant_promotions_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json b/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json index 35c4091b4ca2..31aa6857c0d6 100644 --- a/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json +++ b/packages/google-shopping-merchant-promotions/samples/generated_samples/snippet_metadata_google.shopping.merchant.promotions.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-promotions", - "version": "0.1.0" + "version": "0.1.6" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-quota/CHANGELOG.md b/packages/google-shopping-merchant-quota/CHANGELOG.md index a04234f4992a..5a533497d7a6 100644 --- a/packages/google-shopping-merchant-quota/CHANGELOG.md +++ b/packages/google-shopping-merchant-quota/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.6](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-quota-v0.1.5...google-shopping-merchant-quota-v0.1.6) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.5](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-quota-v0.1.4...google-shopping-merchant-quota-v0.1.5) (2024-12-12) diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py index 558c8aab67c5..51d2795b9d6b 100644 --- a/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-quota/google/shopping/merchant_quota_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.6" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json b/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json index 48037ddf7f53..def869383df4 100644 --- a/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json +++ b/packages/google-shopping-merchant-quota/samples/generated_samples/snippet_metadata_google.shopping.merchant.quota.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-quota", - "version": "0.1.0" + "version": "0.1.6" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-reports/CHANGELOG.md b/packages/google-shopping-merchant-reports/CHANGELOG.md index cf25e0b61cdc..ccbc35dec40d 100644 --- a/packages/google-shopping-merchant-reports/CHANGELOG.md +++ b/packages/google-shopping-merchant-reports/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.13](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-reports-v0.1.12...google-shopping-merchant-reports-v0.1.13) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.12](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-reports-v0.1.11...google-shopping-merchant-reports-v0.1.12) (2024-12-12) diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py index 558c8aab67c5..7daf9a1dd221 100644 --- a/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-reports/google/shopping/merchant_reports_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.13" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json b/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json index 145fa5b7eb46..d161a01ed6db 100644 --- a/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json +++ b/packages/google-shopping-merchant-reports/samples/generated_samples/snippet_metadata_google.shopping.merchant.reports.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-reports", - "version": "0.1.0" + "version": "0.1.13" }, "snippets": [ { diff --git a/packages/google-shopping-merchant-reviews/CHANGELOG.md b/packages/google-shopping-merchant-reviews/CHANGELOG.md index ab4e32dc7d17..37804710888f 100644 --- a/packages/google-shopping-merchant-reviews/CHANGELOG.md +++ b/packages/google-shopping-merchant-reviews/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.1](https://github.com/googleapis/google-cloud-python/compare/google-shopping-merchant-reviews-v0.1.0...google-shopping-merchant-reviews-v0.1.1) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## 0.1.0 (2024-12-12) diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py index 558c8aab67c5..0c7cc68730c4 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.1" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py index 558c8aab67c5..0c7cc68730c4 100644 --- a/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py +++ b/packages/google-shopping-merchant-reviews/google/shopping/merchant_reviews_v1beta/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.1" # {x-release-please-version} diff --git a/packages/google-shopping-merchant-reviews/samples/generated_samples/snippet_metadata_google.shopping.merchant.reviews.v1beta.json b/packages/google-shopping-merchant-reviews/samples/generated_samples/snippet_metadata_google.shopping.merchant.reviews.v1beta.json index d238dd3a6b9b..d5c0e80f8003 100644 --- a/packages/google-shopping-merchant-reviews/samples/generated_samples/snippet_metadata_google.shopping.merchant.reviews.v1beta.json +++ b/packages/google-shopping-merchant-reviews/samples/generated_samples/snippet_metadata_google.shopping.merchant.reviews.v1beta.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-merchant-reviews", - "version": "0.1.0" + "version": "0.1.1" }, "snippets": [ { diff --git a/packages/google-shopping-type/CHANGELOG.md b/packages/google-shopping-type/CHANGELOG.md index f642b919f1b2..3a2a851c0863 100644 --- a/packages/google-shopping-type/CHANGELOG.md +++ b/packages/google-shopping-type/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.10](https://github.com/googleapis/google-cloud-python/compare/google-shopping-type-v0.1.9...google-shopping-type-v0.1.10) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [0.1.9](https://github.com/googleapis/google-cloud-python/compare/google-shopping-type-v0.1.8...google-shopping-type-v0.1.9) (2024-10-24) diff --git a/packages/google-shopping-type/google/shopping/type/gapic_version.py b/packages/google-shopping-type/google/shopping/type/gapic_version.py index 558c8aab67c5..9413c3341313 100644 --- a/packages/google-shopping-type/google/shopping/type/gapic_version.py +++ b/packages/google-shopping-type/google/shopping/type/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "0.1.10" # {x-release-please-version} diff --git a/packages/googleapis-common-protos/CHANGELOG.md b/packages/googleapis-common-protos/CHANGELOG.md index d891131c7ef8..60f60effaef5 100644 --- a/packages/googleapis-common-protos/CHANGELOG.md +++ b/packages/googleapis-common-protos/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [1.68.0](https://github.com/googleapis/google-cloud-python/compare/googleapis-common-protos-v1.67.0...googleapis-common-protos-v1.68.0) (2025-02-18) + + +### Features + +* A new field `unversioned_package_disabled` is added to message `.google.api.PythonSettings` ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab)) +* Add field `experimental_features` to message `PythonSettings` ([#249](https://github.com/googleapis/google-cloud-python/issues/249)) ([ba8d36e](https://github.com/googleapis/google-cloud-python/commit/ba8d36e4a288c57be235c8597e11208359b072b5)) +* add FieldInfo.referenced_types for generics ([#247](https://github.com/googleapis/google-cloud-python/issues/247)) ([c91900a](https://github.com/googleapis/google-cloud-python/commit/c91900ab232e542905cd4f3cf282677bc6bcaab3)) +* add support for field generate_omitted_as_internal in selective gapic generation ([#13482](https://github.com/googleapis/google-cloud-python/issues/13482)) ([993ff4d](https://github.com/googleapis/google-cloud-python/commit/993ff4db8ae64ab1ca1b45de2caf118effb003af)) + + +### Documentation + +* A comment for field `content` in message `.google.api.Page` is changed ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab)) +* A comment for message `RoutingRule` is changed ([eb554e8](https://github.com/googleapis/google-cloud-python/commit/eb554e89424f02ea1db58904c6685a90fca6dbab)) + ## [1.67.0](https://github.com/googleapis/google-cloud-python/compare/googleapis-common-protos-v1.66.0...googleapis-common-protos-v1.67.0) (2025-02-12) diff --git a/packages/googleapis-common-protos/setup.py b/packages/googleapis-common-protos/setup.py index 6b524ed0fb03..ab76dea032ec 100644 --- a/packages/googleapis-common-protos/setup.py +++ b/packages/googleapis-common-protos/setup.py @@ -20,7 +20,7 @@ name = "googleapis-common-protos" description = "Common protobufs used in Google APIs" -version = "1.67.0" +version = "1.68.0" release_status = "Development Status :: 5 - Production/Stable" dependencies = [ "protobuf>=3.20.2,<6.0.0.dev0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", diff --git a/packages/grafeas/CHANGELOG.md b/packages/grafeas/CHANGELOG.md index 9b61942a2bbb..9d13e866da9c 100644 --- a/packages/grafeas/CHANGELOG.md +++ b/packages/grafeas/CHANGELOG.md @@ -4,6 +4,14 @@ [1]: https://pypi.org/project/grafeas/#history +## [1.14.0](https://github.com/googleapis/google-cloud-python/compare/grafeas-v1.13.0...grafeas-v1.14.0) (2025-02-18) + + +### Features + +* Add REST Interceptors which support reading metadata ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) +* Add support for reading selective GAPIC generation methods from service YAML ([30b675e](https://github.com/googleapis/google-cloud-python/commit/30b675e7e9eaee87f9e7bdf4dc910b01f6a3044f)) + ## [1.13.0](https://github.com/googleapis/google-cloud-python/compare/grafeas-v1.12.1...grafeas-v1.13.0) (2024-12-12) diff --git a/packages/grafeas/grafeas/grafeas/gapic_version.py b/packages/grafeas/grafeas/grafeas/gapic_version.py index 558c8aab67c5..2159c8af6f8e 100644 --- a/packages/grafeas/grafeas/grafeas/gapic_version.py +++ b/packages/grafeas/grafeas/grafeas/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.0" # {x-release-please-version} diff --git a/packages/grafeas/grafeas/grafeas_v1/gapic_version.py b/packages/grafeas/grafeas/grafeas_v1/gapic_version.py index 558c8aab67c5..2159c8af6f8e 100644 --- a/packages/grafeas/grafeas/grafeas_v1/gapic_version.py +++ b/packages/grafeas/grafeas/grafeas_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.0.0" # {x-release-please-version} +__version__ = "1.14.0" # {x-release-please-version} diff --git a/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json b/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json index 290215d3171d..4e85dcec096b 100644 --- a/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json +++ b/packages/grafeas/samples/generated_samples/snippet_metadata_grafeas.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "grafeas", - "version": "0.1.0" + "version": "1.14.0" }, "snippets": [ {