Skip to content
This repository was archived by the owner on Sep 5, 2023. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: googleapis/python-recommendations-ai
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.1.0
Choose a base ref
...
head repository: googleapis/python-recommendations-ai
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.2.0
Choose a head ref
  • 3 commits
  • 131 files changed
  • 3 contributors

Commits on Sep 24, 2020

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    fe7e6ed View commit details

Commits on Mar 29, 2021

  1. chore: regenerate (#22)

    fix: BREAKING rename `PriceRange.min` to `PriceRange.min_`, `PriceRange.max` to `PriceRange.max_`
    
    fix: fix bug with enums closes #14, #20
    
    feat: add async clients
    
    feat: add common resource helper methods
    yoshi-automation authored Mar 29, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f8e3d0f View commit details
  2. chore: release 0.2.0 (#23)

    Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
    release-please[bot] authored Mar 29, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3c56c3c View commit details
Showing with 18,354 additions and 2,721 deletions.
  1. +20 −1 .flake8
  2. +11 −0 .github/CODEOWNERS
  3. +1 −2 .github/ISSUE_TEMPLATE/bug_report.md
  4. +15 −0 .github/header-checker-lint.yml
  5. 0 .github/snippet-bot.yml
  6. +7 −2 .gitignore
  7. +26 −6 .kokoro/build.sh
  8. +98 −0 .kokoro/docker/docs/Dockerfile
  9. +45 −0 .kokoro/docker/docs/fetch_gpg_keys.sh
  10. +19 −2 .kokoro/docs/common.cfg
  11. +28 −0 .kokoro/docs/docs-presubmit.cfg
  12. +43 −0 .kokoro/populate-secrets.sh
  13. +24 −17 .kokoro/publish-docs.sh
  14. +0 −2 .kokoro/release.sh
  15. +13 −37 .kokoro/release/common.cfg
  16. +34 −0 .kokoro/samples/lint/common.cfg
  17. +6 −0 .kokoro/samples/lint/continuous.cfg
  18. +6 −0 .kokoro/samples/lint/periodic.cfg
  19. +6 −0 .kokoro/samples/lint/presubmit.cfg
  20. +40 −0 .kokoro/samples/python3.6/common.cfg
  21. +7 −0 .kokoro/samples/python3.6/continuous.cfg
  22. +11 −0 .kokoro/samples/python3.6/periodic-head.cfg
  23. +6 −0 .kokoro/samples/python3.6/periodic.cfg
  24. +6 −0 .kokoro/samples/python3.6/presubmit.cfg
  25. +40 −0 .kokoro/samples/python3.7/common.cfg
  26. +6 −0 .kokoro/samples/python3.7/continuous.cfg
  27. +11 −0 .kokoro/samples/python3.7/periodic-head.cfg
  28. +6 −0 .kokoro/samples/python3.7/periodic.cfg
  29. +6 −0 .kokoro/samples/python3.7/presubmit.cfg
  30. +40 −0 .kokoro/samples/python3.8/common.cfg
  31. +6 −0 .kokoro/samples/python3.8/continuous.cfg
  32. +11 −0 .kokoro/samples/python3.8/periodic-head.cfg
  33. +6 −0 .kokoro/samples/python3.8/periodic.cfg
  34. +6 −0 .kokoro/samples/python3.8/presubmit.cfg
  35. +28 −0 .kokoro/test-samples-against-head.sh
  36. +102 −0 .kokoro/test-samples-impl.sh
  37. +46 −0 .kokoro/test-samples.sh
  38. +10 −5 .kokoro/trampoline.sh
  39. +487 −0 .kokoro/trampoline_v2.sh
  40. +17 −0 .pre-commit-config.yaml
  41. +52 −0 .trampolinerc
  42. +14 −0 CHANGELOG.md
  43. +87 −36 CODE_OF_CONDUCT.md
  44. +35 −40 CONTRIBUTING.rst
  45. +4 −3 LICENSE
  46. +20 −1 MANIFEST.in
  47. +6 −1 docs/_static/custom.css
  48. +2 −2 docs/_templates/layout.html
  49. +19 −11 docs/conf.py
  50. +3 −1 docs/index.rst
  51. +7 −0 docs/multiprocessing.rst
  52. +11 −0 docs/recommendationengine_v1beta1/catalog_service.rst
  53. +11 −0 docs/recommendationengine_v1beta1/prediction_api_key_registry.rst
  54. +11 −0 docs/recommendationengine_v1beta1/prediction_service.rst
  55. +8 −5 docs/recommendationengine_v1beta1/services.rst
  56. +4 −2 docs/recommendationengine_v1beta1/types.rst
  57. +11 −0 docs/recommendationengine_v1beta1/user_event_service.rst
  58. +17 −2 google/cloud/recommendationengine/__init__.py
  59. +3 −4 google/cloud/recommendationengine_v1beta1/__init__.py
  60. +1 −1 google/cloud/recommendationengine_v1beta1/services/__init__.py
  61. +6 −2 google/cloud/recommendationengine_v1beta1/services/catalog_service/__init__.py
  62. +778 −0 google/cloud/recommendationengine_v1beta1/services/catalog_service/async_client.py
  63. +480 −101 google/cloud/recommendationengine_v1beta1/services/catalog_service/client.py
  64. +88 −11 google/cloud/recommendationengine_v1beta1/services/catalog_service/pagers.py
  65. +8 −3 google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/__init__.py
  66. +172 −24 google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/base.py
  67. +144 −38 google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/grpc.py
  68. +424 −0 google/cloud/recommendationengine_v1beta1/services/catalog_service/transports/grpc_asyncio.py
  69. +6 −2 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/__init__.py
  70. +470 −0 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/async_client.py
  71. +405 −53 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/client.py
  72. +103 −12 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/pagers.py
  73. +8 −3 ...le/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/__init__.py
  74. +116 −14 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/base.py
  75. +137 −30 google/cloud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/grpc.py
  76. +336 −0 ...loud/recommendationengine_v1beta1/services/prediction_api_key_registry/transports/grpc_asyncio.py
  77. +6 −2 google/cloud/recommendationengine_v1beta1/services/prediction_service/__init__.py
  78. +327 −0 google/cloud/recommendationengine_v1beta1/services/prediction_service/async_client.py
  79. +330 −28 google/cloud/recommendationengine_v1beta1/services/prediction_service/client.py
  80. +90 −10 google/cloud/recommendationengine_v1beta1/services/prediction_service/pagers.py
  81. +8 −3 google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/__init__.py
  82. +76 −8 google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/base.py
  83. +135 −28 google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/grpc.py
  84. +262 −0 google/cloud/recommendationengine_v1beta1/services/prediction_service/transports/grpc_asyncio.py
  85. +6 −2 google/cloud/recommendationengine_v1beta1/services/user_event_service/__init__.py
  86. +864 −0 google/cloud/recommendationengine_v1beta1/services/user_event_service/async_client.py
  87. +626 −112 google/cloud/recommendationengine_v1beta1/services/user_event_service/client.py
  88. +88 −11 google/cloud/recommendationengine_v1beta1/services/user_event_service/pagers.py
  89. +8 −3 google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/__init__.py
  90. +153 −22 google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/base.py
  91. +146 −40 google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/grpc.py
  92. +407 −0 google/cloud/recommendationengine_v1beta1/services/user_event_service/transports/grpc_asyncio.py
  93. +73 −67 google/cloud/recommendationengine_v1beta1/types/__init__.py
  94. +48 −21 google/cloud/recommendationengine_v1beta1/types/catalog.py
  95. +16 −9 google/cloud/recommendationengine_v1beta1/types/catalog_service.py
  96. +7 −6 google/cloud/recommendationengine_v1beta1/types/common.py
  97. +53 −34 google/cloud/recommendationengine_v1beta1/types/import_.py
  98. +9 −5 google/cloud/recommendationengine_v1beta1/types/prediction_apikey_registry_service.py
  99. +28 −13 google/cloud/recommendationengine_v1beta1/types/prediction_service.py
  100. +24 −0 google/cloud/recommendationengine_v1beta1/types/recommendationengine_resources.py
  101. +55 −25 google/cloud/recommendationengine_v1beta1/types/user_event.py
  102. +21 −9 google/cloud/recommendationengine_v1beta1/types/user_event_service.py
  103. +1 −1 mypy.ini
  104. +107 −22 noxfile.py
  105. +2 −1 renovate.json
  106. +46 −0 scripts/decrypt-secrets.sh
  107. +193 −0 scripts/fixup_recommendationengine_v1beta1_keywords.py
  108. +66 −0 scripts/readme-gen/readme_gen.py
  109. +87 −0 scripts/readme-gen/templates/README.tmpl.rst
  110. +9 −0 scripts/readme-gen/templates/auth.tmpl.rst
  111. +14 −0 scripts/readme-gen/templates/auth_api_key.tmpl.rst
  112. +29 −0 scripts/readme-gen/templates/install_deps.tmpl.rst
  113. +35 −0 scripts/readme-gen/templates/install_portaudio.tmpl.rst
  114. +16 −0 setup.cfg
  115. +4 −7 setup.py
  116. +16 −9 synth.metadata
  117. +68 −23 synth.py
  118. +3 −0 testing/.gitignore
  119. +9 −0 testing/constraints-3.6.txt
  120. +2 −0 testing/constraints-3.7.txt
  121. +2 −0 testing/constraints-3.8.txt
  122. +2 −0 testing/constraints-3.9.txt
  123. +16 −0 tests/unit/gapic/recommendationengine_v1beta1/__init__.py
  124. +2,650 −0 tests/unit/gapic/recommendationengine_v1beta1/test_catalog_service.py
  125. +2,020 −0 tests/unit/gapic/recommendationengine_v1beta1/test_prediction_api_key_registry.py
  126. +1,380 −0 tests/unit/gapic/recommendationengine_v1beta1/test_prediction_service.py
  127. +2,404 −0 tests/unit/gapic/recommendationengine_v1beta1/test_user_event_service.py
  128. +0 −614 tests/unit/recommendationengine_v1beta1/test_catalog_service.py
  129. +0 −387 tests/unit/recommendationengine_v1beta1/test_prediction_api_key_registry.py
  130. +0 −265 tests/unit/recommendationengine_v1beta1/test_prediction_service.py
  131. +0 −458 tests/unit/recommendationengine_v1beta1/test_user_event_service.py
21 changes: 20 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
# -*- coding: utf-8 -*-
#
# Copyright 2020 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
#
# https://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.

# Generated by synthtool. DO NOT EDIT!
[flake8]
ignore = E203, E266, E501, W503, F401, F841
ignore = E203, E266, E501, W503
exclude =
# Exclude generated code.
**/proto/**
**/gapic/**
**/services/**
**/types/**
*_pb2.py

# Standard linting exemptions.
**/.nox/**
__pycache__,
.git,
*.pyc,
11 changes: 11 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Code owners file.
# This file controls who is tagged for review for any given pull request.
#
# For syntax help see:
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax

# The @googleapis/yoshi-python is the default owner for changes in this repo
* @googleapis/yoshi-python

# The python-samples-reviewers team is the default owner for samples changes
/samples/ @googleapis/python-samples-owners
3 changes: 1 addition & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -11,8 +11,7 @@ Thanks for stopping by to let us know something could be better!
Please run down the following list and make sure you've tried the usual "quick fixes":

- Search the issues already opened: https://github.com/googleapis/python-recommendations-ai/issues
- Search the issues on our "catch-all" repository: https://github.com/googleapis/google-cloud-python
- Search StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform+python
- Search StackOverflow: https://stackoverflow.com/questions/tagged/google-cloud-platform+python

If you are still having issues, please be sure to include as much information as possible:

15 changes: 15 additions & 0 deletions .github/header-checker-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{"allowedCopyrightHolders": ["Google LLC"],
"allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"],
"ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"],
"sourceFileExtensions": [
"ts",
"js",
"java",
"sh",
"Dockerfile",
"yaml",
"py",
"html",
"txt"
]
}
Empty file added .github/snippet-bot.yml
Empty file.
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
dist
build
eggs
.eggs
parts
bin
var
@@ -44,15 +45,19 @@ pip-log.txt

# Built documentation
docs/_build
htmlcov
bigquery/docs/generated
docs.metadata

# Virtual environment
env/

# Test logs
coverage.xml
*sponge_log.xml

# System test environment variables.
system_tests/local_test_setup

# Make sure a generated file isn't accidentally committed.
pylintrc
pylintrc.test
pylintrc.test
32 changes: 26 additions & 6 deletions .kokoro/build.sh
Original file line number Diff line number Diff line change
@@ -15,7 +15,11 @@

set -eo pipefail

cd github/python-recommendations-ai
if [[ -z "${PROJECT_ROOT:-}" ]]; then
PROJECT_ROOT="github/python-recommendations-ai"
fi

cd "${PROJECT_ROOT}"

# Disable buffering, so that the logs stream through.
export PYTHONUNBUFFERED=1
@@ -30,10 +34,26 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json
export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json")

# Remove old nox
python3.6 -m pip uninstall --yes --quiet nox-automation
python3 -m pip uninstall --yes --quiet nox-automation

# Install nox
python3.6 -m pip install --upgrade --quiet nox
python3.6 -m nox --version

python3.6 -m nox
python3 -m pip install --upgrade --quiet nox
python3 -m nox --version

# If this is a continuous build, send the test log to the FlakyBot.
# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot.
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then
cleanup() {
chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot
$KOKORO_GFILE_DIR/linux_amd64/flakybot
}
trap cleanup EXIT HUP
fi

# If NOX_SESSION is set, it only runs the specified session,
# otherwise run all the sessions.
if [[ -n "${NOX_SESSION:-}" ]]; then
python3 -m nox -s ${NOX_SESSION:-}
else
python3 -m nox
fi
98 changes: 98 additions & 0 deletions .kokoro/docker/docs/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright 2020 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 ubuntu:20.04

ENV DEBIAN_FRONTEND noninteractive

# Ensure local Python is preferred over distribution Python.
ENV PATH /usr/local/bin:$PATH

# Install dependencies.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apt-transport-https \
build-essential \
ca-certificates \
curl \
dirmngr \
git \
gpg-agent \
graphviz \
libbz2-dev \
libdb5.3-dev \
libexpat1-dev \
libffi-dev \
liblzma-dev \
libreadline-dev \
libsnappy-dev \
libssl-dev \
libsqlite3-dev \
portaudio19-dev \
redis-server \
software-properties-common \
ssh \
sudo \
tcl \
tcl-dev \
tk \
tk-dev \
uuid-dev \
wget \
zlib1g-dev \
&& add-apt-repository universe \
&& apt-get update \
&& apt-get -y install jq \
&& apt-get clean autoclean \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* \
&& rm -f /var/cache/apt/archives/*.deb


COPY fetch_gpg_keys.sh /tmp
# Install the desired versions of Python.
RUN set -ex \
&& export GNUPGHOME="$(mktemp -d)" \
&& echo "disable-ipv6" >> "${GNUPGHOME}/dirmngr.conf" \
&& /tmp/fetch_gpg_keys.sh \
&& for PYTHON_VERSION in 3.7.8 3.8.5; do \
wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \
&& wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \
&& gpg --batch --verify python-${PYTHON_VERSION}.tar.xz.asc python-${PYTHON_VERSION}.tar.xz \
&& rm -r python-${PYTHON_VERSION}.tar.xz.asc \
&& mkdir -p /usr/src/python-${PYTHON_VERSION} \
&& tar -xJC /usr/src/python-${PYTHON_VERSION} --strip-components=1 -f python-${PYTHON_VERSION}.tar.xz \
&& rm python-${PYTHON_VERSION}.tar.xz \
&& cd /usr/src/python-${PYTHON_VERSION} \
&& ./configure \
--enable-shared \
# This works only on Python 2.7 and throws a warning on every other
# version, but seems otherwise harmless.
--enable-unicode=ucs4 \
--with-system-ffi \
--without-ensurepip \
&& make -j$(nproc) \
&& make install \
&& ldconfig \
; done \
&& rm -rf "${GNUPGHOME}" \
&& rm -rf /usr/src/python* \
&& rm -rf ~/.cache/

RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \
&& python3.7 /tmp/get-pip.py \
&& python3.8 /tmp/get-pip.py \
&& rm /tmp/get-pip.py

CMD ["python3.7"]
45 changes: 45 additions & 0 deletions .kokoro/docker/docs/fetch_gpg_keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash
# Copyright 2020 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.

# A script to fetch gpg keys with retry.
# Avoid jinja parsing the file.
#

function retry {
if [[ "${#}" -le 1 ]]; then
echo "Usage: ${0} retry_count commands.."
exit 1
fi
local retries=${1}
local command="${@:2}"
until [[ "${retries}" -le 0 ]]; do
$command && return 0
if [[ $? -ne 0 ]]; then
echo "command failed, retrying"
((retries--))
fi
done
return 1
}

# 3.6.9, 3.7.5 (Ned Deily)
retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \
0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D

# 3.8.0 (Łukasz Langa)
retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \
E3FF2839C048B25C084DEBE9B26995E310250568

#
21 changes: 19 additions & 2 deletions .kokoro/docs/common.cfg
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@ action {
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "python-recommendations-ai/.kokoro/trampoline.sh"
build_file: "python-recommendations-ai/.kokoro/trampoline_v2.sh"

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/python-multi"
value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs"
}
env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
@@ -28,6 +28,23 @@ env_vars: {
value: "docs-staging"
}

env_vars: {
key: "V2_STAGING_BUCKET"
value: "docs-staging-v2"
}

# It will upload the docker image after successful builds.
env_vars: {
key: "TRAMPOLINE_IMAGE_UPLOAD"
value: "true"
}

# It will always build the docker image.
env_vars: {
key: "TRAMPOLINE_DOCKERFILE"
value: ".kokoro/docker/docs/Dockerfile"
}

# Fetch the token needed for reporting release status to GitHub
before_action {
fetch_keystore {
28 changes: 28 additions & 0 deletions .kokoro/docs/docs-presubmit.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "STAGING_BUCKET"
value: "gcloud-python-test"
}

env_vars: {
key: "V2_STAGING_BUCKET"
value: "gcloud-python-test"
}

# We only upload the image in the main `docs` build.
env_vars: {
key: "TRAMPOLINE_IMAGE_UPLOAD"
value: "false"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-recommendations-ai/.kokoro/build.sh"
}

# Only run this nox session.
env_vars: {
key: "NOX_SESSION"
value: "docs docfx"
}
43 changes: 43 additions & 0 deletions .kokoro/populate-secrets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash
# Copyright 2020 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.

set -eo pipefail

function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;}
function msg { println "$*" >&2 ;}
function println { printf '%s\n' "$(now) $*" ;}


# Populates requested secrets set in SECRET_MANAGER_KEYS from service account:
# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com
SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager"
msg "Creating folder on disk for secrets: ${SECRET_LOCATION}"
mkdir -p ${SECRET_LOCATION}
for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g")
do
msg "Retrieving secret ${key}"
docker run --entrypoint=gcloud \
--volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \
gcr.io/google.com/cloudsdktool/cloud-sdk \
secrets versions access latest \
--project cloud-devrel-kokoro-resources \
--secret ${key} > \
"${SECRET_LOCATION}/${key}"
if [[ $? == 0 ]]; then
msg "Secret written to ${SECRET_LOCATION}/${key}"
else
msg "Error retrieving secret ${key}"
fi
done
41 changes: 24 additions & 17 deletions .kokoro/publish-docs.sh
Original file line number Diff line number Diff line change
@@ -13,33 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.

#!/bin/bash

set -eo pipefail

# Disable buffering, so that the logs stream through.
export PYTHONUNBUFFERED=1

cd github/python-recommendations-ai

# Remove old nox
python3.6 -m pip uninstall --yes --quiet nox-automation
export PATH="${HOME}/.local/bin:${PATH}"

# Install nox
python3.6 -m pip install --upgrade --quiet nox
python3.6 -m nox --version
python3 -m pip install --user --upgrade --quiet nox
python3 -m nox --version

# build docs
nox -s docs

python3 -m pip install gcp-docuploader

# install a json parser
sudo apt-get update
sudo apt-get -y install software-properties-common
sudo add-apt-repository universe
sudo apt-get update
sudo apt-get -y install jq
python3 -m pip install --user gcp-docuploader

# create metadata
python3 -m docuploader create-metadata \
@@ -54,4 +42,23 @@ python3 -m docuploader create-metadata \
cat docs.metadata

# upload docs
python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket docs-staging
python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}"


# docfx yaml files
nox -s docfx

# create metadata.
python3 -m docuploader create-metadata \
--name=$(jq --raw-output '.name // empty' .repo-metadata.json) \
--version=$(python3 setup.py --version) \
--language=$(jq --raw-output '.language // empty' .repo-metadata.json) \
--distribution-name=$(python3 setup.py --name) \
--product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \
--github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \
--issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json)

cat docs.metadata

# upload docs
python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}"
2 changes: 0 additions & 2 deletions .kokoro/release.sh
Original file line number Diff line number Diff line change
@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

#!/bin/bash

set -eo pipefail

# Start the releasetool reporter
50 changes: 13 additions & 37 deletions .kokoro/release/common.cfg
Original file line number Diff line number Diff line change
@@ -23,42 +23,18 @@ env_vars: {
value: "github/python-recommendations-ai/.kokoro/release.sh"
}

# Fetch the token needed for reporting release status to GitHub
before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "yoshi-automation-github-key"
}
}
}

# Fetch PyPI password
before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "google_cloud_pypi_password"
}
}
}

# Fetch magictoken to use with Magic Github Proxy
before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "releasetool-magictoken"
}
}
# Fetch PyPI password
before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "google_cloud_pypi_password"
}
}
}

# Fetch api key to use with Magic Github Proxy
before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "magic-github-proxy-api-key"
}
}
}
# Tokens needed to report release status back to GitHub
env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem"
}
34 changes: 34 additions & 0 deletions .kokoro/samples/lint/common.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Build logs will be here
action {
define_artifacts {
regex: "**/*sponge_log.xml"
}
}

# Specify which tests to run
env_vars: {
key: "RUN_TESTS_SESSION"
value: "lint"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-recommendations-ai/.kokoro/test-samples.sh"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker"
}

# Download secrets for samples
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "python-recommendations-ai/.kokoro/trampoline.sh"
6 changes: 6 additions & 0 deletions .kokoro/samples/lint/continuous.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/lint/periodic.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/lint/presubmit.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
40 changes: 40 additions & 0 deletions .kokoro/samples/python3.6/common.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Build logs will be here
action {
define_artifacts {
regex: "**/*sponge_log.xml"
}
}

# Specify which tests to run
env_vars: {
key: "RUN_TESTS_SESSION"
value: "py-3.6"
}

# Declare build specific Cloud project.
env_vars: {
key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
value: "python-docs-samples-tests-py36"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-recommendations-ai/.kokoro/test-samples.sh"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker"
}

# Download secrets for samples
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "python-recommendations-ai/.kokoro/trampoline.sh"
7 changes: 7 additions & 0 deletions .kokoro/samples/python3.6/continuous.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}

11 changes: 11 additions & 0 deletions .kokoro/samples/python3.6/periodic-head.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-pubsub/.kokoro/test-samples-against-head.sh"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.6/periodic.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.6/presubmit.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
40 changes: 40 additions & 0 deletions .kokoro/samples/python3.7/common.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Build logs will be here
action {
define_artifacts {
regex: "**/*sponge_log.xml"
}
}

# Specify which tests to run
env_vars: {
key: "RUN_TESTS_SESSION"
value: "py-3.7"
}

# Declare build specific Cloud project.
env_vars: {
key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
value: "python-docs-samples-tests-py37"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-recommendations-ai/.kokoro/test-samples.sh"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker"
}

# Download secrets for samples
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "python-recommendations-ai/.kokoro/trampoline.sh"
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.7/continuous.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
11 changes: 11 additions & 0 deletions .kokoro/samples/python3.7/periodic-head.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-pubsub/.kokoro/test-samples-against-head.sh"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.7/periodic.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.7/presubmit.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
40 changes: 40 additions & 0 deletions .kokoro/samples/python3.8/common.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Build logs will be here
action {
define_artifacts {
regex: "**/*sponge_log.xml"
}
}

# Specify which tests to run
env_vars: {
key: "RUN_TESTS_SESSION"
value: "py-3.8"
}

# Declare build specific Cloud project.
env_vars: {
key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
value: "python-docs-samples-tests-py38"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-recommendations-ai/.kokoro/test-samples.sh"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker"
}

# Download secrets for samples
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples"

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "python-recommendations-ai/.kokoro/trampoline.sh"
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.8/continuous.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
11 changes: 11 additions & 0 deletions .kokoro/samples/python3.8/periodic-head.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}

env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-pubsub/.kokoro/test-samples-against-head.sh"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.8/periodic.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "False"
}
6 changes: 6 additions & 0 deletions .kokoro/samples/python3.8/presubmit.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Format: //devtools/kokoro/config/proto/build.proto

env_vars: {
key: "INSTALL_LIBRARY_FROM_SOURCE"
value: "True"
}
28 changes: 28 additions & 0 deletions .kokoro/test-samples-against-head.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
# Copyright 2020 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
#
# https://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.

# A customized test runner for samples.
#
# For periodic builds, you can specify this file for testing against head.

# `-e` enables the script to automatically fail when a command fails
# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero
set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar

cd github/python-recommendations-ai

exec .kokoro/test-samples-impl.sh
102 changes: 102 additions & 0 deletions .kokoro/test-samples-impl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/bash
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://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.


# `-e` enables the script to automatically fail when a command fails
# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero
set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar

# Exit early if samples directory doesn't exist
if [ ! -d "./samples" ]; then
echo "No tests run. `./samples` not found"
exit 0
fi

# Disable buffering, so that the logs stream through.
export PYTHONUNBUFFERED=1

# Debug: show build environment
env | grep KOKORO

# Install nox
python3.6 -m pip install --upgrade --quiet nox

# Use secrets acessor service account to get secrets
if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then
gcloud auth activate-service-account \
--key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \
--project="cloud-devrel-kokoro-resources"
fi

# This script will create 3 files:
# - testing/test-env.sh
# - testing/service-account.json
# - testing/client-secrets.json
./scripts/decrypt-secrets.sh

source ./testing/test-env.sh
export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json

# For cloud-run session, we activate the service account for gcloud sdk.
gcloud auth activate-service-account \
--key-file "${GOOGLE_APPLICATION_CREDENTIALS}"

export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json

echo -e "\n******************** TESTING PROJECTS ********************"

# Switch to 'fail at end' to allow all tests to complete before exiting.
set +e
# Use RTN to return a non-zero value if the test fails.
RTN=0
ROOT=$(pwd)
# Find all requirements.txt in the samples directory (may break on whitespace).
for file in samples/**/requirements.txt; do
cd "$ROOT"
# Navigate to the project folder.
file=$(dirname "$file")
cd "$file"

echo "------------------------------------------------------------"
echo "- testing $file"
echo "------------------------------------------------------------"

# Use nox to execute the tests for the project.
python3.6 -m nox -s "$RUN_TESTS_SESSION"
EXIT=$?

# If this is a periodic build, send the test log to the FlakyBot.
# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot.
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot
$KOKORO_GFILE_DIR/linux_amd64/flakybot
fi

if [[ $EXIT -ne 0 ]]; then
RTN=1
echo -e "\n Testing failed: Nox returned a non-zero exit code. \n"
else
echo -e "\n Testing completed.\n"
fi

done
cd "$ROOT"

# Workaround for Kokoro permissions issue: delete secrets
rm testing/{test-env.sh,client-secrets.json,service-account.json}

exit "$RTN"
46 changes: 46 additions & 0 deletions .kokoro/test-samples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash
# Copyright 2020 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
#
# https://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.

# The default test runner for samples.
#
# For periodic builds, we rewinds the repo to the latest release, and
# run test-samples-impl.sh.

# `-e` enables the script to automatically fail when a command fails
# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero
set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar

cd github/python-recommendations-ai

# Run periodic samples tests at latest release
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
# preserving the test runner implementation.
cp .kokoro/test-samples-impl.sh "${TMPDIR}/test-samples-impl.sh"
echo "--- IMPORTANT IMPORTANT IMPORTANT ---"
echo "Now we rewind the repo back to the latest release..."
LATEST_RELEASE=$(git describe --abbrev=0 --tags)
git checkout $LATEST_RELEASE
echo "The current head is: "
echo $(git rev-parse --verify HEAD)
echo "--- IMPORTANT IMPORTANT IMPORTANT ---"
# move back the test runner implementation if there's no file.
if [ ! -f .kokoro/test-samples-impl.sh ]; then
cp "${TMPDIR}/test-samples-impl.sh" .kokoro/test-samples-impl.sh
fi
fi

exec .kokoro/test-samples-impl.sh
15 changes: 10 additions & 5 deletions .kokoro/trampoline.sh
Original file line number Diff line number Diff line change
@@ -15,9 +15,14 @@

set -eo pipefail

python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" || ret_code=$?
# Always run the cleanup script, regardless of the success of bouncing into
# the container.
function cleanup() {
chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
echo "cleanup";
}
trap cleanup EXIT

chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
${KOKORO_GFILE_DIR}/trampoline_cleanup.sh || true

exit ${ret_code}
$(dirname $0)/populate-secrets.sh # Secret Manager secrets.
python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py"
487 changes: 487 additions & 0 deletions .kokoro/trampoline_v2.sh

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/psf/black
rev: 19.10b0
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.0
hooks:
- id: flake8
52 changes: 52 additions & 0 deletions .trampolinerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright 2020 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.

# Template for .trampolinerc

# Add required env vars here.
required_envvars+=(
"STAGING_BUCKET"
"V2_STAGING_BUCKET"
)

# Add env vars which are passed down into the container here.
pass_down_envvars+=(
"STAGING_BUCKET"
"V2_STAGING_BUCKET"
"NOX_SESSION"
)

# Prevent unintentional override on the default image.
if [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]] && \
[[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then
echo "Please set TRAMPOLINE_IMAGE if you want to upload the Docker image."
exit 1
fi

# Define the default value if it makes sense.
if [[ -z "${TRAMPOLINE_IMAGE_UPLOAD:-}" ]]; then
TRAMPOLINE_IMAGE_UPLOAD=""
fi

if [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then
TRAMPOLINE_IMAGE=""
fi

if [[ -z "${TRAMPOLINE_DOCKERFILE:-}" ]]; then
TRAMPOLINE_DOCKERFILE=""
fi

if [[ -z "${TRAMPOLINE_BUILD_FILE:-}" ]]; then
TRAMPOLINE_BUILD_FILE=""
fi
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## [0.2.0](https://www.github.com/googleapis/python-recommendations-ai/compare/v0.1.0...v0.2.0) (2021-03-29)


### Features

* add async clients ([f8e3d0f](https://www.github.com/googleapis/python-recommendations-ai/commit/f8e3d0f8d12921b926c24cf33e10c4d4390164bb))
* add common resource helper methods ([f8e3d0f](https://www.github.com/googleapis/python-recommendations-ai/commit/f8e3d0f8d12921b926c24cf33e10c4d4390164bb))


### Bug Fixes

* BREAKING rename `PriceRange.min` to `PriceRange.min_`, `PriceRange.max` to `PriceRange.max_` ([f8e3d0f](https://www.github.com/googleapis/python-recommendations-ai/commit/f8e3d0f8d12921b926c24cf33e10c4d4390164bb))
* fix bug with enums closes [#14](https://www.github.com/googleapis/python-recommendations-ai/issues/14), [#20](https://www.github.com/googleapis/python-recommendations-ai/issues/20) ([f8e3d0f](https://www.github.com/googleapis/python-recommendations-ai/commit/f8e3d0f8d12921b926c24cf33e10c4d4390164bb))

## 0.1.0 (2020-03-13)


123 changes: 87 additions & 36 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,95 @@
<!-- # Generated by synthtool. DO NOT EDIT! !-->
# Contributor Code of Conduct
# Code of Conduct

As contributors and maintainers of this project,
and in the interest of fostering an open and welcoming community,
we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
## Our Pledge

We are committed to making participation in this project
a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of
experience, education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information,
such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct.
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct.
By adopting this Code of Conduct,
project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project.
Project maintainers who do not follow or enforce the Code of Conduct
may be permanently removed from the project team.

This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported by opening an issue
or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, or to ban temporarily or permanently any
contributor for other behaviors that they deem inappropriate, threatening,
offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

This Code of Conduct also applies outside the project spaces when the Project
Steward has a reasonable belief that an individual's behavior may have a
negative impact on the project or its community.

## Conflict Resolution

We do not believe that all conflict is bad; healthy debate and disagreement
often yield positive results. However, it is never okay to be disrespectful or
to engage in behavior that violates the project’s code of conduct.

If you see someone violating the code of conduct, you are encouraged to address
the behavior directly with those involved. Many issues can be resolved quickly
and easily, and this gives people more control over the outcome of their
dispute. If you are unable to resolve the matter for any reason, or if the
behavior is threatening or harassing, report it. We are dedicated to providing
an environment where participants feel welcome and safe.


Reports should be directed to *googleapis-stewards@google.com*, the
Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to
receive and address reported violations of the code of conduct. They will then
work with a committee consisting of representatives from the Open Source
Programs Office and the Google Open Source Strategy team. If for any reason you
are uncomfortable reaching out to the Project Steward, please email
opensource@google.com.

We will investigate every complaint, but you may not receive a direct response.
We will use our discretion in determining when and how to follow up on reported
incidents, which may range from not taking action to permanent expulsion from
the project and project-sponsored spaces. We will notify the accused of the
report and provide them an opportunity to discuss it before any action is taken.
The identity of the reporter will be omitted from the details of the report
supplied to the accused. In potentially harmful situations, such as ongoing
harassment or threats to anyone's safety, we may take action without notice.

## Attribution

This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
available at
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
75 changes: 35 additions & 40 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
@@ -21,8 +21,8 @@ In order to add a feature:
- The feature must be documented in both the API and narrative
documentation.

- The feature must work fully on the following CPython versions: 2.7,
3.5, 3.6, and 3.7 on both UNIX and Windows.
- The feature must work fully on the following CPython versions:
3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows.

- The feature must not add unnecessary dependencies (where
"unnecessary" is of course subjective, but new dependencies should
@@ -70,35 +70,21 @@ We use `nox <https://nox.readthedocs.io/en/latest/>`__ to instrument our tests.
- To test your changes, run unit tests with ``nox``::

$ nox -s unit-2.7
$ nox -s unit-3.7
$ nox -s unit-3.8
$ ...

- Args to pytest can be passed through the nox command separated by a `--`. For
example, to run a single test::

$ nox -s unit-3.8 -- -k <name of test>

.. note::

The unit tests and system tests are described in the
``noxfile.py`` files in each directory.

.. nox: https://pypi.org/project/nox/
Note on Editable Installs / Develop Mode
========================================

- As mentioned previously, using ``setuptools`` in `develop mode`_
or a ``pip`` `editable install`_ is not possible with this
library. This is because this library uses `namespace packages`_.
For context see `Issue #2316`_ and the relevant `PyPA issue`_.

Since ``editable`` / ``develop`` mode can't be used, packages
need to be installed directly. Hence your changes to the source
tree don't get incorporated into the **already installed**
package.

.. _namespace packages: https://www.python.org/dev/peps/pep-0420/
.. _Issue #2316: https://github.com/GoogleCloudPlatform/google-cloud-python/issues/2316
.. _PyPA issue: https://github.com/pypa/packaging-problems/issues/12
.. _develop mode: https://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode
.. _editable install: https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs

*****************************************
I'm getting weird errors... Can you help?
*****************************************
@@ -112,8 +98,12 @@ On Debian/Ubuntu::
************
Coding Style
************
- We use the automatic code formatter ``black``. You can run it using
the nox session ``blacken``. This will eliminate many lint errors. Run via::

- PEP8 compliance, with exceptions defined in the linter configuration.
$ nox -s blacken

- PEP8 compliance is required, with exceptions defined in the linter configuration.
If you have ``nox`` installed, you can test that you have not introduced
any non-compliant code via::

@@ -130,6 +120,16 @@ Coding Style
should point to the official ``googleapis`` checkout and the
the branch should be the main branch on that remote (``master``).

- This repository contains configuration for the
`pre-commit <https://pre-commit.com/>`__ tool, which automates checking
our linters during a commit. If you have it installed on your ``$PATH``,
you can enable enforcing those checks via:

.. code-block:: bash
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
Exceptions to PEP8:

- Many unit tests use a helper method, ``_call_fut`` ("FUT" is short for
@@ -142,13 +142,18 @@ Running System Tests

- To run system tests, you can execute::

$ nox -s system-3.7
# Run all system tests
$ nox -s system-3.8
$ nox -s system-2.7

# Run a single system test
$ nox -s system-3.8 -- -k <name of test>


.. note::

System tests are only configured to run under Python 2.7 and
Python 3.7. For expediency, we do not run them in older versions
Python 3.8. For expediency, we do not run them in older versions
of Python 3.

This alone will not run the tests. You'll need to change some local
@@ -211,33 +216,24 @@ Supported Python Versions

We support:

- `Python 3.5`_
- `Python 3.6`_
- `Python 3.7`_
- `Python 3.8`_
- `Python 3.9`_

.. _Python 3.5: https://docs.python.org/3.5/
.. _Python 3.6: https://docs.python.org/3.6/
.. _Python 3.7: https://docs.python.org/3.7/
.. _Python 3.8: https://docs.python.org/3.8/
.. _Python 3.9: https://docs.python.org/3.9/


Supported versions can be found in our ``noxfile.py`` `config`_.

.. _config: https://github.com/googleapis/python-recommendations-ai/blob/master/noxfile.py

We explicitly decided not to support `Python 2.5`_ due to `decreased usage`_
and lack of continuous integration `support`_.

.. _Python 2.5: https://docs.python.org/2.5/
.. _decreased usage: https://caremad.io/2013/10/a-look-at-pypi-downloads/
.. _support: https://blog.travis-ci.com/2013-11-18-upcoming-build-environment-updates/

We have `dropped 2.6`_ as a supported version as well since Python 2.6 is no
longer supported by the core development team.

Python 2.7 support is deprecated. All code changes should maintain Python 2.7 compatibility until January 1, 2020.

We also explicitly decided to support Python 3 beginning with version
3.5. Reasons for this include:
3.6. Reasons for this include:

- Encouraging use of newest versions of Python 3
- Taking the lead of `prominent`_ open-source `projects`_
@@ -247,7 +243,6 @@ We also explicitly decided to support Python 3 beginning with version
.. _prominent: https://docs.djangoproject.com/en/1.9/faq/install/#what-python-version-can-i-use-with-django
.. _projects: http://flask.pocoo.org/docs/0.10/python3/
.. _Unicode literal support: https://www.python.org/dev/peps/pep-0414/
.. _dropped 2.6: https://github.com/googleapis/google-cloud-python/issues/995

**********
Versioning
7 changes: 4 additions & 3 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Apache License

Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

@@ -192,7 +193,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0
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,
21 changes: 20 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
# -*- coding: utf-8 -*-
#
# Copyright 2020 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
#
# https://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.

# Generated by synthtool. DO NOT EDIT!
include README.rst LICENSE
recursive-include google *.json *.proto
recursive-include google *.json *.proto py.typed
recursive-include tests *
global-exclude *.py[co]
global-exclude __pycache__

# Exclude scripts for samples readmegen
prune scripts/readme-gen
7 changes: 6 additions & 1 deletion docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
div#python2-eol {
border-color: red;
border-width: medium;
}
}

/* Ensure minimum width for 'Parameters' / 'Returns' column */
dl.field-list > dt {
min-width: 100px
}
4 changes: 2 additions & 2 deletions docs/_templates/layout.html
Original file line number Diff line number Diff line change
@@ -21,8 +21,8 @@

<div class="body" role="main">
<div class="admonition" id="python2-eol">
On January 1, 2020 this library will no longer support Python 2 on the latest released version.
Previously released library versions will continue to be available. For more information please
As of January 1, 2020 this library no longer supports Python 2 on the latest released version.
Library versions released prior to that date will continue to be available. For more information please
visit <a href="https://cloud.google.com/python/docs/python2-sunset/">Python 2 support on Google Cloud</a>.
</div>
{% block body %} {% endblock %}
30 changes: 19 additions & 11 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -20,12 +20,16 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(".."))

# For plugins that can not read conf.py.
# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85
sys.path.insert(0, os.path.abspath("."))

__version__ = ""

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "1.6.3"
needs_sphinx = "1.5.5"

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -35,24 +39,22 @@
"sphinx.ext.autosummary",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
"sphinx.ext.doctest",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
"sphinx.ext.viewcode",
"recommonmark",
]

# autodoc/autosummary flags
autoclass_content = "both"
autodoc_default_flags = ["members"]
autodoc_default_options = {"members": True}
autosummary_generate = True


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# Allow markdown includes (so releases.md can include CHANGLEOG.md)
# http://www.sphinx-doc.org/en/master/markdown.html
source_parsers = {".md": "recommonmark.parser.CommonMarkParser"}

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
@@ -93,7 +95,12 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
exclude_patterns = [
"_build",
"samples/AUTHORING_GUIDE.md",
"samples/CONTRIBUTING.md",
"samples/snippets/README.rst",
]

# The reST default role (used for this markup: `text`) to use for all
# documents.
@@ -338,10 +345,11 @@

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
"python": ("http://python.readthedocs.org/en/latest/", None),
"google-auth": ("https://google-auth.readthedocs.io/en/stable", None),
"google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None),
"grpc": ("https://grpc.io/grpc/python/", None),
"python": ("https://python.readthedocs.org/en/latest/", None),
"google-auth": ("https://googleapis.dev/python/google-auth/latest/", None),
"google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None,),
"grpc": ("https://grpc.github.io/grpc/python/", None),
"proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None),
}


4 changes: 3 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.. include:: README.rst

.. include:: multiprocessing.rst

API Reference
-------------
.. toctree::
@@ -16,4 +18,4 @@ For a list of all ``google-cloud-recommendations-ai`` releases:
.. toctree::
:maxdepth: 2

changelog
changelog
7 changes: 7 additions & 0 deletions docs/multiprocessing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. note::

Because this client uses :mod:`grpcio` library, it is safe to
share instances across threads. In multiprocessing scenarios, the best
practice is to create client instances *after* the invocation of
:func:`os.fork` by :class:`multiprocessing.Pool` or
:class:`multiprocessing.Process`.
11 changes: 11 additions & 0 deletions docs/recommendationengine_v1beta1/catalog_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CatalogService
--------------------------------

.. automodule:: google.cloud.recommendationengine_v1beta1.services.catalog_service
:members:
:inherited-members:


.. automodule:: google.cloud.recommendationengine_v1beta1.services.catalog_service.pagers
:members:
:inherited-members:
11 changes: 11 additions & 0 deletions docs/recommendationengine_v1beta1/prediction_api_key_registry.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PredictionApiKeyRegistry
------------------------------------------

.. automodule:: google.cloud.recommendationengine_v1beta1.services.prediction_api_key_registry
:members:
:inherited-members:


.. automodule:: google.cloud.recommendationengine_v1beta1.services.prediction_api_key_registry.pagers
:members:
:inherited-members:
11 changes: 11 additions & 0 deletions docs/recommendationengine_v1beta1/prediction_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PredictionService
-----------------------------------

.. automodule:: google.cloud.recommendationengine_v1beta1.services.prediction_service
:members:
:inherited-members:


.. automodule:: google.cloud.recommendationengine_v1beta1.services.prediction_service.pagers
:members:
:inherited-members:
13 changes: 8 additions & 5 deletions docs/recommendationengine_v1beta1/services.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Client for Google Cloud Recommendationengine API
================================================
Services for Google Cloud Recommendationengine v1beta1 API
==========================================================
.. toctree::
:maxdepth: 2

.. automodule:: google.cloud.recommendationengine_v1beta1
:members:
:inherited-members:
catalog_service
prediction_api_key_registry
prediction_service
user_event_service
6 changes: 4 additions & 2 deletions docs/recommendationengine_v1beta1/types.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Types for Google Cloud Recommendationengine API
===============================================
Types for Google Cloud Recommendationengine v1beta1 API
=======================================================

.. automodule:: google.cloud.recommendationengine_v1beta1.types
:members:
:undoc-members:
:show-inheritance:
11 changes: 11 additions & 0 deletions docs/recommendationengine_v1beta1/user_event_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
UserEventService
----------------------------------

.. automodule:: google.cloud.recommendationengine_v1beta1.services.user_event_service
:members:
:inherited-members:


.. automodule:: google.cloud.recommendationengine_v1beta1.services.user_event_service.pagers
:members:
:inherited-members:
19 changes: 17 additions & 2 deletions google/cloud/recommendationengine/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,16 +15,27 @@
# limitations under the License.
#


from google.cloud.recommendationengine_v1beta1.services.catalog_service.async_client import (
CatalogServiceAsyncClient,
)
from google.cloud.recommendationengine_v1beta1.services.catalog_service.client import (
CatalogServiceClient,
)
from google.cloud.recommendationengine_v1beta1.services.prediction_api_key_registry.async_client import (
PredictionApiKeyRegistryAsyncClient,
)
from google.cloud.recommendationengine_v1beta1.services.prediction_api_key_registry.client import (
PredictionApiKeyRegistryClient,
)
from google.cloud.recommendationengine_v1beta1.services.prediction_service.async_client import (
PredictionServiceAsyncClient,
)
from google.cloud.recommendationengine_v1beta1.services.prediction_service.client import (
PredictionServiceClient,
)
from google.cloud.recommendationengine_v1beta1.services.user_event_service.async_client import (
UserEventServiceAsyncClient,
)
from google.cloud.recommendationengine_v1beta1.services.user_event_service.client import (
UserEventServiceClient,
)
@@ -129,6 +140,7 @@
__all__ = (
"CatalogInlineSource",
"CatalogItem",
"CatalogServiceAsyncClient",
"CatalogServiceClient",
"CollectUserEventRequest",
"CreateCatalogItemRequest",
@@ -156,7 +168,9 @@
"PredictRequest",
"PredictResponse",
"PredictionApiKeyRegistration",
"PredictionApiKeyRegistryAsyncClient",
"PredictionApiKeyRegistryClient",
"PredictionServiceAsyncClient",
"PredictionServiceClient",
"ProductCatalogItem",
"ProductDetail",
@@ -169,6 +183,7 @@
"UserEvent",
"UserEventImportSummary",
"UserEventInlineSource",
"UserEventServiceAsyncClient",
"UserEventServiceClient",
"UserInfo",
"WriteUserEventRequest",
7 changes: 3 additions & 4 deletions google/cloud/recommendationengine_v1beta1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
# limitations under the License.
#


from .services.catalog_service import CatalogServiceClient
from .services.prediction_api_key_registry import PredictionApiKeyRegistryClient
from .services.prediction_service import PredictionServiceClient
@@ -74,6 +73,7 @@
__all__ = (
"CatalogInlineSource",
"CatalogItem",
"CatalogServiceClient",
"CollectUserEventRequest",
"CreateCatalogItemRequest",
"CreatePredictionApiKeyRegistrationRequest",
@@ -113,8 +113,7 @@
"UserEvent",
"UserEventImportSummary",
"UserEventInlineSource",
"UserEventServiceClient",
"UserInfo",
"WriteUserEventRequest",
"CatalogServiceClient",
"UserEventServiceClient",
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,5 +16,9 @@
#

from .client import CatalogServiceClient
from .async_client import CatalogServiceAsyncClient

__all__ = ("CatalogServiceClient",)
__all__ = (
"CatalogServiceClient",
"CatalogServiceAsyncClient",
)

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,16 @@
# limitations under the License.
#

from typing import Any, Callable, Iterable
from typing import (
Any,
AsyncIterable,
Awaitable,
Callable,
Iterable,
Sequence,
Tuple,
Optional,
)

from google.cloud.recommendationengine_v1beta1.types import catalog
from google.cloud.recommendationengine_v1beta1.types import catalog_service
@@ -25,7 +34,7 @@ class ListCatalogItemsPager:
"""A pager for iterating through ``list_catalog_items`` requests.
This class thinly wraps an initial
:class:`~.catalog_service.ListCatalogItemsResponse` object, and
:class:`google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse` object, and
provides an ``__iter__`` method to iterate through its
``catalog_items`` field.
@@ -34,33 +43,35 @@ class ListCatalogItemsPager:
through the ``catalog_items`` field on the
corresponding responses.
All the usual :class:`~.catalog_service.ListCatalogItemsResponse`
All the usual :class:`google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""

def __init__(
self,
method: Callable[
[catalog_service.ListCatalogItemsRequest],
catalog_service.ListCatalogItemsResponse,
],
method: Callable[..., catalog_service.ListCatalogItemsResponse],
request: catalog_service.ListCatalogItemsRequest,
response: catalog_service.ListCatalogItemsResponse,
*,
metadata: Sequence[Tuple[str, str]] = ()
):
"""Instantiate the pager.
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
request (:class:`~.catalog_service.ListCatalogItemsRequest`):
request (google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsRequest):
The initial request object.
response (:class:`~.catalog_service.ListCatalogItemsResponse`):
response (google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
"""
self._method = method
self._request = catalog_service.ListCatalogItemsRequest(request)
self._response = response
self._metadata = metadata

def __getattr__(self, name: str) -> Any:
return getattr(self._response, name)
@@ -70,7 +81,7 @@ def pages(self) -> Iterable[catalog_service.ListCatalogItemsResponse]:
yield self._response
while self._response.next_page_token:
self._request.page_token = self._response.next_page_token
self._response = self._method(self._request)
self._response = self._method(self._request, metadata=self._metadata)
yield self._response

def __iter__(self) -> Iterable[catalog.CatalogItem]:
@@ -79,3 +90,69 @@ def __iter__(self) -> Iterable[catalog.CatalogItem]:

def __repr__(self) -> str:
return "{0}<{1!r}>".format(self.__class__.__name__, self._response)


class ListCatalogItemsAsyncPager:
"""A pager for iterating through ``list_catalog_items`` requests.
This class thinly wraps an initial
:class:`google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse` object, and
provides an ``__aiter__`` method to iterate through its
``catalog_items`` field.
If there are more pages, the ``__aiter__`` method will make additional
``ListCatalogItems`` requests and continue to iterate
through the ``catalog_items`` field on the
corresponding responses.
All the usual :class:`google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""

def __init__(
self,
method: Callable[..., Awaitable[catalog_service.ListCatalogItemsResponse]],
request: catalog_service.ListCatalogItemsRequest,
response: catalog_service.ListCatalogItemsResponse,
*,
metadata: Sequence[Tuple[str, str]] = ()
):
"""Instantiate the pager.
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
request (google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsRequest):
The initial request object.
response (google.cloud.recommendationengine_v1beta1.types.ListCatalogItemsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
"""
self._method = method
self._request = catalog_service.ListCatalogItemsRequest(request)
self._response = response
self._metadata = metadata

def __getattr__(self, name: str) -> Any:
return getattr(self._response, name)

@property
async def pages(self) -> AsyncIterable[catalog_service.ListCatalogItemsResponse]:
yield self._response
while self._response.next_page_token:
self._request.page_token = self._response.next_page_token
self._response = await self._method(self._request, metadata=self._metadata)
yield self._response

def __aiter__(self) -> AsyncIterable[catalog.CatalogItem]:
async def async_generator():
async for page in self.pages:
for response in page.catalog_items:
yield response

return async_generator()

def __repr__(self) -> str:
return "{0}<{1!r}>".format(self.__class__.__name__, self._response)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,11 +20,16 @@

from .base import CatalogServiceTransport
from .grpc import CatalogServiceGrpcTransport
from .grpc_asyncio import CatalogServiceGrpcAsyncIOTransport


# Compile a registry of transports.
_transport_registry = OrderedDict() # type: Dict[str, Type[CatalogServiceTransport]]
_transport_registry["grpc"] = CatalogServiceGrpcTransport
_transport_registry["grpc_asyncio"] = CatalogServiceGrpcAsyncIOTransport


__all__ = ("CatalogServiceTransport", "CatalogServiceGrpcTransport")
__all__ = (
"CatalogServiceTransport",
"CatalogServiceGrpcTransport",
"CatalogServiceGrpcAsyncIOTransport",
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,8 +17,12 @@

import abc
import typing
import pkg_resources

from google import auth
from google import auth # type: ignore
from google.api_core import exceptions # type: ignore
from google.api_core import gapic_v1 # type: ignore
from google.api_core import retry as retries # type: ignore
from google.api_core import operations_v1 # type: ignore
from google.auth import credentials # type: ignore

@@ -29,7 +33,17 @@
from google.protobuf import empty_pb2 as empty # type: ignore


class CatalogServiceTransport(metaclass=abc.ABCMeta):
try:
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution(
"google-cloud-recommendations-ai",
).version,
)
except pkg_resources.DistributionNotFound:
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()


class CatalogServiceTransport(abc.ABC):
"""Abstract transport class for CatalogService."""

AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",)
@@ -39,6 +53,11 @@ def __init__(
*,
host: str = "recommendationengine.googleapis.com",
credentials: credentials.Credentials = None,
credentials_file: typing.Optional[str] = None,
scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES,
quota_project_id: typing.Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
**kwargs,
) -> None:
"""Instantiate the transport.
@@ -49,67 +68,196 @@ def __init__(
credentials identify the application to the service; if none
are specified, the client will attempt to ascertain the
credentials from the environment.
credentials_file (Optional[str]): A file with credentials that can
be loaded with :func:`google.auth.load_credentials_from_file`.
This argument is mutually exclusive with credentials.
scope (Optional[Sequence[str]]): A list of scopes.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
The client info used to send a user-agent string along with
API requests. If ``None``, then default info will be used.
Generally, you only need to set this if you're developing
your own client library.
"""
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
if ":" not in host:
host += ":443"
self._host = host

# Save the scopes.
self._scopes = scopes or self.AUTH_SCOPES

# If no credentials are provided, then determine the appropriate
# defaults.
if credentials is None:
credentials, _ = auth.default(scopes=self.AUTH_SCOPES)
if credentials and credentials_file:
raise exceptions.DuplicateCredentialArgs(
"'credentials_file' and 'credentials' are mutually exclusive"
)

if credentials_file is not None:
credentials, _ = auth.load_credentials_from_file(
credentials_file, scopes=self._scopes, quota_project_id=quota_project_id
)

elif credentials is None:
credentials, _ = auth.default(
scopes=self._scopes, quota_project_id=quota_project_id
)

# Save the credentials.
self._credentials = credentials

def _prep_wrapped_messages(self, client_info):
# Precompute the wrapped methods.
self._wrapped_methods = {
self.create_catalog_item: gapic_v1.method.wrap_method(
self.create_catalog_item,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.get_catalog_item: gapic_v1.method.wrap_method(
self.get_catalog_item,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.list_catalog_items: gapic_v1.method.wrap_method(
self.list_catalog_items,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.update_catalog_item: gapic_v1.method.wrap_method(
self.update_catalog_item,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.delete_catalog_item: gapic_v1.method.wrap_method(
self.delete_catalog_item,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.import_catalog_items: gapic_v1.method.wrap_method(
self.import_catalog_items,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
}

@property
def operations_client(self) -> operations_v1.OperationsClient:
"""Return the client designed to process long-running operations."""
raise NotImplementedError
raise NotImplementedError()

@property
def create_catalog_item(
self
self,
) -> typing.Callable[
[catalog_service.CreateCatalogItemRequest], catalog.CatalogItem
[catalog_service.CreateCatalogItemRequest],
typing.Union[catalog.CatalogItem, typing.Awaitable[catalog.CatalogItem]],
]:
raise NotImplementedError
raise NotImplementedError()

@property
def get_catalog_item(
self
) -> typing.Callable[[catalog_service.GetCatalogItemRequest], catalog.CatalogItem]:
raise NotImplementedError
self,
) -> typing.Callable[
[catalog_service.GetCatalogItemRequest],
typing.Union[catalog.CatalogItem, typing.Awaitable[catalog.CatalogItem]],
]:
raise NotImplementedError()

@property
def list_catalog_items(
self
self,
) -> typing.Callable[
[catalog_service.ListCatalogItemsRequest],
catalog_service.ListCatalogItemsResponse,
typing.Union[
catalog_service.ListCatalogItemsResponse,
typing.Awaitable[catalog_service.ListCatalogItemsResponse],
],
]:
raise NotImplementedError
raise NotImplementedError()

@property
def update_catalog_item(
self
self,
) -> typing.Callable[
[catalog_service.UpdateCatalogItemRequest], catalog.CatalogItem
[catalog_service.UpdateCatalogItemRequest],
typing.Union[catalog.CatalogItem, typing.Awaitable[catalog.CatalogItem]],
]:
raise NotImplementedError
raise NotImplementedError()

@property
def delete_catalog_item(
self
) -> typing.Callable[[catalog_service.DeleteCatalogItemRequest], empty.Empty]:
raise NotImplementedError
self,
) -> typing.Callable[
[catalog_service.DeleteCatalogItemRequest],
typing.Union[empty.Empty, typing.Awaitable[empty.Empty]],
]:
raise NotImplementedError()

@property
def import_catalog_items(
self
) -> typing.Callable[[import_.ImportCatalogItemsRequest], operations.Operation]:
raise NotImplementedError
self,
) -> typing.Callable[
[import_.ImportCatalogItemsRequest],
typing.Union[operations.Operation, typing.Awaitable[operations.Operation]],
]:
raise NotImplementedError()


__all__ = ("CatalogServiceTransport",)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,11 +15,15 @@
# limitations under the License.
#

from typing import Callable, Dict
import warnings
from typing import Callable, Dict, Optional, Sequence, Tuple

from google.api_core import grpc_helpers # type: ignore
from google.api_core import operations_v1 # type: ignore
from google.api_core import gapic_v1 # type: ignore
from google import auth # type: ignore
from google.auth import credentials # type: ignore
from google.auth.transport.grpc import SslCredentials # type: ignore

import grpc # type: ignore

@@ -29,7 +33,7 @@
from google.longrunning import operations_pb2 as operations # type: ignore
from google.protobuf import empty_pb2 as empty # type: ignore

from .base import CatalogServiceTransport
from .base import CatalogServiceTransport, DEFAULT_CLIENT_INFO


class CatalogServiceGrpcTransport(CatalogServiceTransport):
@@ -46,12 +50,22 @@ class CatalogServiceGrpcTransport(CatalogServiceTransport):
top of HTTP/2); the ``grpcio`` package must be installed.
"""

_stubs: Dict[str, Callable]

def __init__(
self,
*,
host: str = "recommendationengine.googleapis.com",
credentials: credentials.Credentials = None,
channel: grpc.Channel = None
credentials_file: str = None,
scopes: Sequence[str] = None,
channel: grpc.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id: Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the transport.
@@ -63,61 +77,155 @@ def __init__(
are specified, the client will attempt to ascertain the
credentials from the environment.
This argument is ignored if ``channel`` is provided.
credentials_file (Optional[str]): A file with credentials that can
be loaded with :func:`google.auth.load_credentials_from_file`.
This argument is ignored if ``channel`` is provided.
scopes (Optional(Sequence[str])): A list of scopes. This argument is
ignored if ``channel`` is provided.
channel (Optional[grpc.Channel]): A ``Channel`` instance through
which to make calls.
api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint.
If provided, it overrides the ``host`` argument and tries to create
a mutual TLS channel with client SSL credentials from
``client_cert_source`` or applicatin default SSL credentials.
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]):
Deprecated. A callback to provide client SSL certificate bytes and
private key bytes, both in PEM format. It is ignored if
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
A callback to provide client certificate bytes and private key bytes,
both in PEM format. It is used to configure mutual TLS channel. It is
ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
The client info used to send a user-agent string along with
API requests. If ``None``, then default info will be used.
Generally, you only need to set this if you're developing
your own client library.
Raises:
google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
creation failed for any reason.
google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
and ``credentials_file`` are passed.
"""
# Sanity check: Ensure that channel and credentials are not both
# provided.
if channel:
credentials = False
self._grpc_channel = None
self._ssl_channel_credentials = ssl_channel_credentials
self._stubs: Dict[str, Callable] = {}
self._operations_client = None

# Run the base constructor.
super().__init__(host=host, credentials=credentials)
self._stubs = {} # type: Dict[str, Callable]
if api_mtls_endpoint:
warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
if client_cert_source:
warnings.warn("client_cert_source is deprecated", DeprecationWarning)

# If a channel was explicitly provided, set it.
if channel:
# Ignore credentials if a channel was passed.
credentials = False
# If a channel was explicitly provided, set it.
self._grpc_channel = channel
self._ssl_channel_credentials = None

else:
if api_mtls_endpoint:
host = api_mtls_endpoint

# Create SSL credentials with client_cert_source or application
# default SSL credentials.
if client_cert_source:
cert, key = client_cert_source()
self._ssl_channel_credentials = grpc.ssl_channel_credentials(
certificate_chain=cert, private_key=key
)
else:
self._ssl_channel_credentials = SslCredentials().ssl_credentials

else:
if client_cert_source_for_mtls and not ssl_channel_credentials:
cert, key = client_cert_source_for_mtls()
self._ssl_channel_credentials = grpc.ssl_channel_credentials(
certificate_chain=cert, private_key=key
)

# The base transport sets the host, credentials and scopes
super().__init__(
host=host,
credentials=credentials,
credentials_file=credentials_file,
scopes=scopes,
quota_project_id=quota_project_id,
client_info=client_info,
)

if not self._grpc_channel:
self._grpc_channel = type(self).create_channel(
self._host,
credentials=self._credentials,
credentials_file=credentials_file,
scopes=self._scopes,
ssl_credentials=self._ssl_channel_credentials,
quota_project_id=quota_project_id,
options=[
("grpc.max_send_message_length", -1),
("grpc.max_receive_message_length", -1),
],
)

# Wrap messages. This must be done after self._grpc_channel exists
self._prep_wrapped_messages(client_info)

@classmethod
def create_channel(
cls,
host: str = "recommendationengine.googleapis.com",
credentials: credentials.Credentials = None,
**kwargs
credentials_file: str = None,
scopes: Optional[Sequence[str]] = None,
quota_project_id: Optional[str] = None,
**kwargs,
) -> grpc.Channel:
"""Create and return a gRPC channel object.
Args:
address (Optionsl[str]): The host for the channel to use.
host (Optional[str]): The host for the channel to use.
credentials (Optional[~.Credentials]): The
authorization credentials to attach to requests. These
credentials identify this application to the service. If
none are specified, the client will attempt to ascertain
the credentials from the environment.
credentials_file (Optional[str]): A file with credentials that can
be loaded with :func:`google.auth.load_credentials_from_file`.
This argument is mutually exclusive with credentials.
scopes (Optional[Sequence[str]]): A optional list of scopes needed for this
service. These are only used when credentials are not specified and
are passed to :func:`google.auth.default`.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
kwargs (Optional[dict]): Keyword arguments, which are passed to the
channel creation.
Returns:
grpc.Channel: A gRPC channel object.
Raises:
google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
and ``credentials_file`` are passed.
"""
scopes = scopes or cls.AUTH_SCOPES
return grpc_helpers.create_channel(
host, credentials=credentials, scopes=cls.AUTH_SCOPES, **kwargs
host,
credentials=credentials,
credentials_file=credentials_file,
scopes=scopes,
quota_project_id=quota_project_id,
**kwargs,
)

@property
def grpc_channel(self) -> grpc.Channel:
"""Create the channel designed to connect to this service.
This property caches on the instance; repeated calls return
the same channel.
"""Return the channel designed to connect to this service.
"""
# Sanity check: Only create a new channel if we do not already
# have one.
if not hasattr(self, "_grpc_channel"):
self._grpc_channel = self.create_channel(
self._host, credentials=self._credentials
)

# Return the channel from cache.
return self._grpc_channel

@property
@@ -128,17 +236,15 @@ def operations_client(self) -> operations_v1.OperationsClient:
client.
"""
# Sanity check: Only create a new client if we do not already have one.
if "operations_client" not in self.__dict__:
self.__dict__["operations_client"] = operations_v1.OperationsClient(
self.grpc_channel
)
if self._operations_client is None:
self._operations_client = operations_v1.OperationsClient(self.grpc_channel)

# Return the client from cache.
return self.__dict__["operations_client"]
return self._operations_client

@property
def create_catalog_item(
self
self,
) -> Callable[[catalog_service.CreateCatalogItemRequest], catalog.CatalogItem]:
r"""Return a callable for the create catalog item method over gRPC.
@@ -164,7 +270,7 @@ def create_catalog_item(

@property
def get_catalog_item(
self
self,
) -> Callable[[catalog_service.GetCatalogItemRequest], catalog.CatalogItem]:
r"""Return a callable for the get catalog item method over gRPC.
@@ -190,7 +296,7 @@ def get_catalog_item(

@property
def list_catalog_items(
self
self,
) -> Callable[
[catalog_service.ListCatalogItemsRequest],
catalog_service.ListCatalogItemsResponse,
@@ -219,7 +325,7 @@ def list_catalog_items(

@property
def update_catalog_item(
self
self,
) -> Callable[[catalog_service.UpdateCatalogItemRequest], catalog.CatalogItem]:
r"""Return a callable for the update catalog item method over gRPC.
@@ -246,7 +352,7 @@ def update_catalog_item(

@property
def delete_catalog_item(
self
self,
) -> Callable[[catalog_service.DeleteCatalogItemRequest], empty.Empty]:
r"""Return a callable for the delete catalog item method over gRPC.
@@ -272,7 +378,7 @@ def delete_catalog_item(

@property
def import_catalog_items(
self
self,
) -> Callable[[import_.ImportCatalogItemsRequest], operations.Operation]:
r"""Return a callable for the import catalog items method over gRPC.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,5 +16,9 @@
#

from .client import PredictionApiKeyRegistryClient
from .async_client import PredictionApiKeyRegistryAsyncClient

__all__ = ("PredictionApiKeyRegistryClient",)
__all__ = (
"PredictionApiKeyRegistryClient",
"PredictionApiKeyRegistryAsyncClient",
)

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,16 @@
# limitations under the License.
#

from typing import Any, Callable, Iterable
from typing import (
Any,
AsyncIterable,
Awaitable,
Callable,
Iterable,
Sequence,
Tuple,
Optional,
)

from google.cloud.recommendationengine_v1beta1.types import (
prediction_apikey_registry_service,
@@ -26,7 +35,7 @@ class ListPredictionApiKeyRegistrationsPager:
"""A pager for iterating through ``list_prediction_api_key_registrations`` requests.
This class thinly wraps an initial
:class:`~.prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse` object, and
:class:`google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse` object, and
provides an ``__iter__`` method to iterate through its
``prediction_api_key_registrations`` field.
@@ -35,58 +44,140 @@ class ListPredictionApiKeyRegistrationsPager:
through the ``prediction_api_key_registrations`` field on the
corresponding responses.
All the usual :class:`~.prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse`
All the usual :class:`google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""

def __init__(
self,
method: Callable[
[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest
],
...,
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse,
],
request: prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest,
response: prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse,
*,
metadata: Sequence[Tuple[str, str]] = ()
):
"""Instantiate the pager.
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
request (:class:`~.prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest`):
request (google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsRequest):
The initial request object.
response (:class:`~.prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse`):
response (google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
"""
self._method = method
self._request = prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest(
request
)
self._response = response
self._metadata = metadata

def __getattr__(self, name: str) -> Any:
return getattr(self._response, name)

@property
def pages(
self
self,
) -> Iterable[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse
]:
yield self._response
while self._response.next_page_token:
self._request.page_token = self._response.next_page_token
self._response = self._method(self._request)
self._response = self._method(self._request, metadata=self._metadata)
yield self._response

def __iter__(
self
self,
) -> Iterable[prediction_apikey_registry_service.PredictionApiKeyRegistration]:
for page in self.pages:
yield from page.prediction_api_key_registrations

def __repr__(self) -> str:
return "{0}<{1!r}>".format(self.__class__.__name__, self._response)


class ListPredictionApiKeyRegistrationsAsyncPager:
"""A pager for iterating through ``list_prediction_api_key_registrations`` requests.
This class thinly wraps an initial
:class:`google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse` object, and
provides an ``__aiter__`` method to iterate through its
``prediction_api_key_registrations`` field.
If there are more pages, the ``__aiter__`` method will make additional
``ListPredictionApiKeyRegistrations`` requests and continue to iterate
through the ``prediction_api_key_registrations`` field on the
corresponding responses.
All the usual :class:`google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse`
attributes are available on the pager. If multiple requests are made, only
the most recent response is retained, and thus used for attribute lookup.
"""

def __init__(
self,
method: Callable[
...,
Awaitable[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse
],
],
request: prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest,
response: prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse,
*,
metadata: Sequence[Tuple[str, str]] = ()
):
"""Instantiate the pager.
Args:
method (Callable): The method that was originally called, and
which instantiated this pager.
request (google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsRequest):
The initial request object.
response (google.cloud.recommendationengine_v1beta1.types.ListPredictionApiKeyRegistrationsResponse):
The initial response object.
metadata (Sequence[Tuple[str, str]]): Strings which should be
sent along with the request as metadata.
"""
self._method = method
self._request = prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest(
request
)
self._response = response
self._metadata = metadata

def __getattr__(self, name: str) -> Any:
return getattr(self._response, name)

@property
async def pages(
self,
) -> AsyncIterable[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse
]:
yield self._response
while self._response.next_page_token:
self._request.page_token = self._response.next_page_token
self._response = await self._method(self._request, metadata=self._metadata)
yield self._response

def __aiter__(
self,
) -> AsyncIterable[prediction_apikey_registry_service.PredictionApiKeyRegistration]:
async def async_generator():
async for page in self.pages:
for response in page.prediction_api_key_registrations:
yield response

return async_generator()

def __repr__(self) -> str:
return "{0}<{1!r}>".format(self.__class__.__name__, self._response)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,13 +20,18 @@

from .base import PredictionApiKeyRegistryTransport
from .grpc import PredictionApiKeyRegistryGrpcTransport
from .grpc_asyncio import PredictionApiKeyRegistryGrpcAsyncIOTransport


# Compile a registry of transports.
_transport_registry = (
OrderedDict()
) # type: Dict[str, Type[PredictionApiKeyRegistryTransport]]
_transport_registry["grpc"] = PredictionApiKeyRegistryGrpcTransport
_transport_registry["grpc_asyncio"] = PredictionApiKeyRegistryGrpcAsyncIOTransport


__all__ = ("PredictionApiKeyRegistryTransport", "PredictionApiKeyRegistryGrpcTransport")
__all__ = (
"PredictionApiKeyRegistryTransport",
"PredictionApiKeyRegistryGrpcTransport",
"PredictionApiKeyRegistryGrpcAsyncIOTransport",
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (C) 2019 Google LLC
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,8 +17,12 @@

import abc
import typing
import pkg_resources

from google import auth
from google import auth # type: ignore
from google.api_core import exceptions # type: ignore
from google.api_core import gapic_v1 # type: ignore
from google.api_core import retry as retries # type: ignore
from google.auth import credentials # type: ignore

from google.cloud.recommendationengine_v1beta1.types import (
@@ -27,7 +31,17 @@
from google.protobuf import empty_pb2 as empty # type: ignore


class PredictionApiKeyRegistryTransport(metaclass=abc.ABCMeta):
try:
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution(
"google-cloud-recommendations-ai",
).version,
)
except pkg_resources.DistributionNotFound:
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()


class PredictionApiKeyRegistryTransport(abc.ABC):
"""Abstract transport class for PredictionApiKeyRegistry."""

AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",)
@@ -37,6 +51,11 @@ def __init__(
*,
host: str = "recommendationengine.googleapis.com",
credentials: credentials.Credentials = None,
credentials_file: typing.Optional[str] = None,
scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES,
quota_project_id: typing.Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
**kwargs,
) -> None:
"""Instantiate the transport.
@@ -47,46 +66,129 @@ def __init__(
credentials identify the application to the service; if none
are specified, the client will attempt to ascertain the
credentials from the environment.
credentials_file (Optional[str]): A file with credentials that can
be loaded with :func:`google.auth.load_credentials_from_file`.
This argument is mutually exclusive with credentials.
scope (Optional[Sequence[str]]): A list of scopes.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
The client info used to send a user-agent string along with
API requests. If ``None``, then default info will be used.
Generally, you only need to set this if you're developing
your own client library.
"""
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
if ":" not in host:
host += ":443"
self._host = host

# Save the scopes.
self._scopes = scopes or self.AUTH_SCOPES

# If no credentials are provided, then determine the appropriate
# defaults.
if credentials is None:
credentials, _ = auth.default(scopes=self.AUTH_SCOPES)
if credentials and credentials_file:
raise exceptions.DuplicateCredentialArgs(
"'credentials_file' and 'credentials' are mutually exclusive"
)

if credentials_file is not None:
credentials, _ = auth.load_credentials_from_file(
credentials_file, scopes=self._scopes, quota_project_id=quota_project_id
)

elif credentials is None:
credentials, _ = auth.default(
scopes=self._scopes, quota_project_id=quota_project_id
)

# Save the credentials.
self._credentials = credentials

def _prep_wrapped_messages(self, client_info):
# Precompute the wrapped methods.
self._wrapped_methods = {
self.create_prediction_api_key_registration: gapic_v1.method.wrap_method(
self.create_prediction_api_key_registration,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.list_prediction_api_key_registrations: gapic_v1.method.wrap_method(
self.list_prediction_api_key_registrations,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
self.delete_prediction_api_key_registration: gapic_v1.method.wrap_method(
self.delete_prediction_api_key_registration,
default_retry=retries.Retry(
initial=0.1,
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=600.0,
),
default_timeout=600.0,
client_info=client_info,
),
}

@property
def create_prediction_api_key_registration(
self
self,
) -> typing.Callable[
[prediction_apikey_registry_service.CreatePredictionApiKeyRegistrationRequest],
prediction_apikey_registry_service.PredictionApiKeyRegistration,
typing.Union[
prediction_apikey_registry_service.PredictionApiKeyRegistration,
typing.Awaitable[
prediction_apikey_registry_service.PredictionApiKeyRegistration
],
],
]:
raise NotImplementedError
raise NotImplementedError()

@property
def list_prediction_api_key_registrations(
self
self,
) -> typing.Callable[
[prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsRequest],
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse,
typing.Union[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse,
typing.Awaitable[
prediction_apikey_registry_service.ListPredictionApiKeyRegistrationsResponse
],
],
]:
raise NotImplementedError
raise NotImplementedError()

@property
def delete_prediction_api_key_registration(
self
self,
) -> typing.Callable[
[prediction_apikey_registry_service.DeletePredictionApiKeyRegistrationRequest],
empty.Empty,
typing.Union[empty.Empty, typing.Awaitable[empty.Empty]],
]:
raise NotImplementedError
raise NotImplementedError()


__all__ = ("PredictionApiKeyRegistryTransport",)
Loading