diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md
new file mode 100644
index 00000000..0f175c59
--- /dev/null
+++ b/.gemini/GEMINI.md
@@ -0,0 +1,12 @@
+# Overview
+
+This codebase is part of the Google Workspace GitHub organization, https://github.com/googleworkspace.
+
+## Style Guide
+
+Use open source best practices for code style and formatting with a preference for Google's style guides.
+
+## Tools
+
+- Verify against Google Workspace documentation with the `workspace-developer` MCP server tools.
+- Use `gh` for GitHub interactions.
diff --git a/.gemini/config.yaml b/.gemini/config.yaml
new file mode 100644
index 00000000..a4814a5f
--- /dev/null
+++ b/.gemini/config.yaml
@@ -0,0 +1,12 @@
+# Config for the Gemini Pull Request Review Bot.
+# https://github.com/marketplace/gemini-code-assist
+have_fun: false
+code_review:
+ disable: false
+ comment_severity_threshold: "HIGH"
+ max_review_comments: -1
+ pull_request_opened:
+ help: false
+ summary: true
+ code_review: true
+ignore_patterns: []
diff --git a/.gemini/settings.json b/.gemini/settings.json
new file mode 100644
index 00000000..ec3565d5
--- /dev/null
+++ b/.gemini/settings.json
@@ -0,0 +1,8 @@
+{
+ "mcpServers": {
+ "workspace-developer": {
+ "httpUrl": "https://workspace-developer.goog/mcp",
+ "trust": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..804a0939
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,17 @@
+# Copyright 2022 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.
+
+# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
+
+.github/ @googleworkspace/workspace-devrel-dpe
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..19768a88
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,116 @@
+version: 2
+updates:
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/admin_sdk/directory"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/admin_sdk/reports"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/admin_sdk/reseller"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/apps_script/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/calendar/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/classroom/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/docs/mail-merge"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/docs/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/drive/activity-v2"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/drive/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/forms/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/gmail/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/gmail/snippet"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/people/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/sheets/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/slides/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/tasks/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
+ - package-ecosystem: "pip"
+ directory: "/vault/quickstart"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore(deps):"
diff --git a/.github/linters/.htmlhintrc b/.github/linters/.htmlhintrc
new file mode 100644
index 00000000..70391a46
--- /dev/null
+++ b/.github/linters/.htmlhintrc
@@ -0,0 +1,25 @@
+{
+ "tagname-lowercase": true,
+ "attr-lowercase": true,
+ "attr-value-double-quotes": true,
+ "attr-value-not-empty": false,
+ "attr-no-duplication": true,
+ "doctype-first": false,
+ "tag-pair": true,
+ "tag-self-close": false,
+ "spec-char-escape": false,
+ "id-unique": true,
+ "src-not-empty": true,
+ "title-require": false,
+ "alt-require": true,
+ "doctype-html5": true,
+ "id-class-value": false,
+ "style-disabled": false,
+ "inline-style-disabled": false,
+ "inline-script-disabled": false,
+ "space-tab-mixed-disabled": "space",
+ "id-class-ad-disabled": false,
+ "href-abs-or-rel": false,
+ "attr-unsafe-chars": true,
+ "head-script-disabled": false
+}
diff --git a/.github/linters/.yaml-lint.yml b/.github/linters/.yaml-lint.yml
new file mode 100644
index 00000000..e8394fd5
--- /dev/null
+++ b/.github/linters/.yaml-lint.yml
@@ -0,0 +1,59 @@
+---
+###########################################
+# These are the rules used for #
+# linting all the yaml files in the stack #
+# NOTE: #
+# You can disable line with: #
+# # yamllint disable-line #
+###########################################
+rules:
+ braces:
+ level: warning
+ min-spaces-inside: 0
+ max-spaces-inside: 0
+ min-spaces-inside-empty: 1
+ max-spaces-inside-empty: 5
+ brackets:
+ level: warning
+ min-spaces-inside: 0
+ max-spaces-inside: 0
+ min-spaces-inside-empty: 1
+ max-spaces-inside-empty: 5
+ colons:
+ level: warning
+ max-spaces-before: 0
+ max-spaces-after: 1
+ commas:
+ level: warning
+ max-spaces-before: 0
+ min-spaces-after: 1
+ max-spaces-after: 1
+ comments: disable
+ comments-indentation: disable
+ document-end: disable
+ document-start:
+ level: warning
+ present: true
+ empty-lines:
+ level: warning
+ max: 2
+ max-start: 0
+ max-end: 0
+ hyphens:
+ level: warning
+ max-spaces-after: 1
+ indentation:
+ level: warning
+ spaces: consistent
+ indent-sequences: true
+ check-multi-line-strings: false
+ key-duplicates: enable
+ line-length:
+ level: warning
+ max: 120
+ allow-non-breakable-words: true
+ allow-non-breakable-inline-mappings: true
+ new-line-at-end-of-file: disable
+ new-lines:
+ type: unix
+ trailing-spaces: disable
\ No newline at end of file
diff --git a/.github/linters/sun_checks.xml b/.github/linters/sun_checks.xml
new file mode 100644
index 00000000..76d0840d
--- /dev/null
+++ b/.github/linters/sun_checks.xml
@@ -0,0 +1,374 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.github/scripts/authorize.sh b/.github/scripts/authorize.sh
index 165b8c1e..a6503421 100755
--- a/.github/scripts/authorize.sh
+++ b/.github/scripts/authorize.sh
@@ -20,6 +20,7 @@
SCOPES=(
"https://www.googleapis.com/auth/drive"
"https://www.googleapis.com/auth/drive.activity"
+ "https://www.googleapis.com/auth/drive.appdata"
"https://mail.google.com/"
"https://www.googleapis.com/auth/classroom.courses"
"https://www.googleapis.com/auth/classroom.announcements"
@@ -41,7 +42,7 @@ fi
printf -v EXPANDED_SCOPES '%s,' "${SCOPES[@]}"
gcloud auth application-default login \
- --client-id-file=client_secret.json \
+ --client-id-file="$CLIENT_ID_FILE" \
--scopes="${EXPANDED_SCOPES}"
cat "${HOME}/.config/gcloud/application_default_credentials.json"
\ No newline at end of file
diff --git a/.github/snippet-bot.yml b/.github/snippet-bot.yml
new file mode 100644
index 00000000..bb488a81
--- /dev/null
+++ b/.github/snippet-bot.yml
@@ -0,0 +1,14 @@
+# Copyright 2022 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.
+
diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml
new file mode 100644
index 00000000..7b363bc4
--- /dev/null
+++ b/.github/sync-repo-settings.yaml
@@ -0,0 +1,41 @@
+# Copyright 2022 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.
+
+# .github/sync-repo-settings.yaml
+# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings for app options.
+rebaseMergeAllowed: true
+squashMergeAllowed: true
+mergeCommitAllowed: false
+deleteBranchOnMerge: true
+branchProtectionRules:
+ - pattern: main
+ isAdminEnforced: false
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ # .github/workflows/test.yml with a job called "test"
+ - "test"
+ # .github/workflows/lint.yml with a job called "lint"
+ - "lint"
+ # Google bots below
+ - "cla/google"
+ - "snippet-bot check"
+ - "header-check"
+ - "conventionalcommits.org"
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+permissionRules:
+ - team: workspace-devrel-dpe
+ permission: admin
+ - team: workspace-devrel
+ permission: push
diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml
new file mode 100644
index 00000000..95f323bf
--- /dev/null
+++ b/.github/workflows/automation.yml
@@ -0,0 +1,69 @@
+# Copyright 2022 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.
+---
+name: Automation
+on: [ push, pull_request, workflow_dispatch ]
+jobs:
+ dependabot:
+ runs-on: ubuntu-latest
+ if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }}
+ env:
+ PR_URL: ${{github.event.pull_request.html_url}}
+ GITHUB_TOKEN: ${{secrets.GOOGLEWORKSPACE_BOT_TOKEN}}
+ steps:
+ - name: approve
+ run: gh pr review --approve "$PR_URL"
+ - name: merge
+ run: gh pr merge --auto --squash --delete-branch "$PR_URL"
+ default-branch-migration:
+ # this job helps with migrating the default branch to main
+ # it pushes main to master if master exists and main is the default branch
+ # it pushes master to main if master is the default branch
+ runs-on: ubuntu-latest
+ if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ # required otherwise GitHub blocks infinite loops in pushes originating in an action
+ token: ${{ secrets.GOOGLEWORKSPACE_BOT_TOKEN }}
+ - name: Set env
+ run: |
+ # set DEFAULT BRANCH
+ echo "DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" >> "$GITHUB_ENV";
+
+ # set HAS_MASTER_BRANCH
+ if [ -n "$(git ls-remote --heads origin master)" ]; then
+ echo "HAS_MASTER_BRANCH=true" >> "$GITHUB_ENV"
+ else
+ echo "HAS_MASTER_BRANCH=false" >> "$GITHUB_ENV"
+ fi
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: configure git
+ run: |
+ git config --global user.name 'googleworkspace-bot'
+ git config --global user.email 'googleworkspace-bot@google.com'
+ - if: ${{ env.DEFAULT_BRANCH == 'main' && env.HAS_MASTER_BRANCH == 'true' }}
+ name: Update master branch from main
+ run: |
+ git checkout -B master
+ git reset --hard origin/main
+ git push origin master
+ - if: ${{ env.DEFAULT_BRANCH == 'master'}}
+ name: Update main branch from master
+ run: |
+ git checkout -B main
+ git reset --hard origin/master
+ git push origin main
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yml
similarity index 86%
rename from .github/workflows/lint.yaml
rename to .github/workflows/lint.yml
index 7b80e396..3dcd20f7 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yml
@@ -12,13 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
name: Lint
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
+on: [push, pull_request, workflow_dispatch]
+
jobs:
lint:
concurrency:
@@ -26,14 +21,15 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-20.04
steps:
- - uses: actions/checkout@v2.4.0
+ - uses: actions/checkout@v3.0.0
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
- - uses: github/super-linter/slim@v4.8.7
+ - uses: github/super-linter/slim@v4.9.0
env:
ERROR_ON_MISSING_EXEC_BIT: true
VALIDATE_JSCPD: false
VALIDATE_PYTHON_BLACK: false
+ VALIDATE_PYTHON_FLAKE8: false
VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/ci.yaml b/.github/workflows/test.yml
similarity index 61%
rename from .github/workflows/ci.yaml
rename to .github/workflows/test.yml
index 2eecea34..2258e628 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/test.yml
@@ -1,29 +1,43 @@
-name: CI
+# Copyright 2022 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.
-on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
+name: Test
+
+on: [push, pull_request, workflow_dispatch]
jobs:
- test:
+ matrix:
+ concurrency:
+ group: ${{ github.head_ref || github.ref }}
+ cancel-in-progress: true
# Only run for internal PRs or after a merge
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
strategy:
matrix:
# TODO - expand matrix once stable
- python-version: [3.6]
+ python-version:
+ - "3.10"
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Fetch and Diff PR with base from which it was cloned
if: ${{ github.event.pull_request.base.sha }}
run: |
git fetch origin master "${{ github.event.pull_request.base.sha }}"
git diff --diff-filter=ACM --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.sha }}" > "${HOME}/changed_files.txt"
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
@@ -42,3 +56,8 @@ jobs:
CLIENT_ID_FILE: ${{secrets.SNIPPETS_CLIENT_ID_FILE}}
- name: Run tests
run: ./.github/scripts/test.sh
+ test:
+ needs: [matrix]
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo "Test matrix finished"
diff --git a/.pylintrc b/.pylintrc
index e67e73ca..ef66b689 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -1,35 +1,33 @@
-[MASTER]
+# This Pylint rcfile contains a best-effort configuration to uphold the
+# best-practices and style described in the Google Python style guide:
+# https://google.github.io/styleguide/pyguide.html
+#
+# Its canonical open-source location is:
+# https://google.github.io/styleguide/pylintrc
-# Specify a configuration file.
-#rcfile=
+[MAIN]
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
+# Files or directories to be skipped. They should be base names, not paths.
+ignore=third_party
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
+# Files or directories matching the regex patterns are skipped. The regex
+# matches against base names, not paths.
+ignore-patterns=
# Pickle collected data for later comparisons.
-persistent=yes
+persistent=no
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
-jobs=1
+jobs=4
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code
-extension-pkg-whitelist=
-
[MESSAGES CONTROL]
@@ -39,7 +37,8 @@ confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
-# multiple time. See also the "--disable" option for examples.
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
@@ -51,78 +50,86 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
-#
-# -----------------------------------------------------------------------
-# 2015-01-12 - What follows is the list of all disabled items necessary
-# to get a clean run of lint across CourseBuilder. These are separated
-# into three tiers:
-#
-# - Fix-worthy. This includes:
-# - Probable bugs
-# - Easily-addressed hygiene issues,
-# - Real warnings which we may mark as suppressed on a case-by-case basis.
-# - Items that are questionable practice, but not necessarily economical to fix.
-# - Items that we intend to ignore, as we do not consider them bad practice.
-#
-# Warning messages are documented at http://docs.pylint.org/features.html
-#
-# ----------------------------------------------------------------------
-# Fix-worthy:
-#
-# ---- Possible bugs:
-# disable=super-on-old-class
-# disable=arguments-differ (# of arguments to overriding/overridden method)
-# disable=signature-differs
-# disable=method-hidden
-# disable=abstract-method (Abstract method not overridden in derived class)
-# disable=no-member (self.foo used when foo not declared in class)
-#
-# ---- Easy-to-fix and improves readability, cleanliness:
-# disable=relative-import
-#
-# ---- Probably legitimate, but needs markup to indicate intentionality
-# disable=no-init (Class does not have __init__, nor do ancestor classes)
-# disable=import-error
-# disable=attribute-defined-outside-init
-#
-# ----------------------------------------------------------------------
-# Fix when economical:
-#
-# ---- Minor code cleanliness problems; fix when encountered.
-# disable=unused-argument
-# disable=unused-variable
-# disable=invalid-name (Variable name does not meet coding standard)
-# disable=duplicate-code
-#
-# ---- Laundry list of tunable parameters for when things are too big/small
-# disable=abstract-class-little-used
-# disable=too-few-public-methods
-# disable=too-many-instance-attributes
-# disable=too-many-ancestors
-# disable=too-many-return-statements
-# disable=too-many-lines
-# disable=too-many-locals
-# disable=too-many-function-args
-# disable=too-many-public-methods
-# disable=too-many-arguments
-#
-# ----------------------------------------------------------------------
-# Ignored; OK by our coding standard:
-#
-# disable=bad-continuation (Bad whitespace on following line)
-# disable=no-self-use (Member function never uses 'self' parameter)
-# disable=missing-docstring
-# disable=fixme
-# disable=star-args
-# disable=locally-disabled (Notes local suppression of warning)
-# disable=locally-enabled (Notes re-enable of suppressed warning)
-# disable=bad-option-value (Notes suppression of unknown warning)
-# disable=abstract-class-not-used (Warns when not used in same file)
-#
-# Unfortunately, since the options parsing does not support multi-line entries
-# nor line continuation, all of the above items are redundantly specified here
-# in a way that pylint is willing to parse.
-disable=super-on-old-class,arguments-differ,signature-differs,method-hidden,abstract-method,no-member,relative-import,no-init,import-error,attribute-defined-outside-init,abstract-class-not-used,unused-argument,unused-variable,invalid-name,duplicate-code,abstract-class-little-used,too-few-public-methods,too-many-instance-attributes,too-many-ancestors,too-many-return-statements,too-many-lines,too-many-locals,too-many-function-args,too-many-public-methods,too-many-arguments,bad-continuation,no-self-use,missing-docstring,fixme,star-args,locally-disabled,locally-enabled,bad-option-value
+disable=R,
+ abstract-method,
+ apply-builtin,
+ arguments-differ,
+ attribute-defined-outside-init,
+ backtick,
+ bad-option-value,
+ basestring-builtin,
+ buffer-builtin,
+ c-extension-no-member,
+ consider-using-enumerate,
+ cmp-builtin,
+ cmp-method,
+ coerce-builtin,
+ coerce-method,
+ delslice-method,
+ div-method,
+ eq-without-hash,
+ execfile-builtin,
+ file-builtin,
+ filter-builtin-not-iterating,
+ fixme,
+ getslice-method,
+ global-statement,
+ hex-method,
+ idiv-method,
+ implicit-str-concat,
+ import-error,
+ import-self,
+ import-star-module-level,
+ input-builtin,
+ intern-builtin,
+ invalid-str-codec,
+ locally-disabled,
+ long-builtin,
+ long-suffix,
+ map-builtin-not-iterating,
+ misplaced-comparison-constant,
+ missing-function-docstring,
+ metaclass-assignment,
+ next-method-called,
+ next-method-defined,
+ no-absolute-import,
+ no-init, # added
+ no-member,
+ no-name-in-module,
+ no-self-use,
+ nonzero-method,
+ oct-method,
+ old-division,
+ old-ne-operator,
+ old-octal-literal,
+ old-raise-syntax,
+ parameter-unpacking,
+ print-statement,
+ raising-string,
+ range-builtin-not-iterating,
+ raw_input-builtin,
+ rdiv-method,
+ reduce-builtin,
+ relative-import,
+ reload-builtin,
+ round-builtin,
+ setslice-method,
+ signature-differs,
+ standarderror-builtin,
+ suppressed-message,
+ sys-max-int,
+ trailing-newlines,
+ unichr-builtin,
+ unicode-builtin,
+ unnecessary-pass,
+ unpacking-in-except,
+ useless-else-on-loop,
+ useless-suppression,
+ using-cmp-argument,
+ wrong-import-order,
+ xrange-builtin,
+ zip-builtin-not-iterating,
+
[REPORTS]
@@ -131,11 +138,6 @@ disable=super-on-old-class,arguments-differ,signature-differs,method-hidden,abst
# mypackage.mymodule.MyReporterClass.
output-format=text
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
# Tells whether to display a full report or only the messages
reports=no
@@ -151,210 +153,203 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme
#msg-template=
-[SPELLING]
-
-# Spelling dictionary name. Available dictionaries: none. To make it working
-# install python-enchant package.
-spelling-dict=
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to indicated private dictionary in
-# --spelling-private-dict-file option instead of raising a message.
-spelling-store-unknown-words=no
-
+[BASIC]
-[SIMILARITIES]
+# Good variable names which should always be accepted, separated by a comma
+good-names=main,_
-# Minimum lines number of a similarity.
-min-similarity-lines=4
+# Bad variable names which should always be refused, separated by a comma
+bad-names=
-# Ignore comments when computing similarities.
-ignore-comments=yes
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
-# Ignore imports when computing similarities.
-ignore-imports=no
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
+# Regular expression matching correct function names
+function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*)|(?P_?[a-z][a-z0-9_]*))$
-[LOGGING]
+# Regular expression matching correct variable names
+variable-rgx=^[a-z][a-z0-9_]*$
-# Logging modules to check that the string format arguments are in logging
-# function parameter format
-logging-modules=logging
+# Regular expression matching correct constant names
+const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+# Regular expression matching correct attribute names
+attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
-[MISCELLANEOUS]
+# Regular expression matching correct argument names
+argument-rgx=^[a-z][a-z0-9_]*$
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
+# Regular expression matching correct class attribute names
+class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=^[a-z][a-z0-9_]*$
-[VARIABLES]
+# Regular expression matching correct class names
+class-rgx=^_?[A-Z][a-zA-Z0-9]*$
-# Tells whether we should check for unused import in __init__ files.
-init-import=yes
+# Regular expression matching correct module names
+module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
-# A regular expression matching the name of dummy variables (i.e. expectedly
-# not used).
-dummy-variables-rgx=_$|dummy
+# Regular expression matching correct method names
+method-rgx=(?x)^(?:(?P_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P_{0,2}[a-z][a-z0-9_]*))$
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,_cb
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=12
[TYPECHECK]
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
+# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
-
+generated-members=
-[BASIC]
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,input
+[FORMAT]
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
+# Maximum number of characters on a single line.
+max-line-length=80
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
+# TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt
+# lines made too long by directives to pytype.
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=(?x)(
+ ^\s*(\#\ )??$|
+ ^\s*(from\s+\S+\s+)?import\s+.+$)
-# Include a hint for the correct naming format with invalid-name
-include-naming-hint=no
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=yes
-# Regular expression matching correct function names
-function-rgx=[a-z_][a-z0-9_]{2,50}$
+# Maximum number of lines in a module
+max-module-lines=99999
-# Naming hint for function names
-function-name-hint=[a-z_][a-z0-9_]{2,50}$
+# String used as indentation unit. The internal Google style guide mandates 2
+# spaces. Google's externaly-published style guide says 4, consistent with
+# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
+# projects (like TensorFlow).
+indent-string=' '
-# Regular expression matching correct variable names
-variable-rgx=[a-z_][a-z0-9_]{1,30}$
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
-# Naming hint for variable names
-variable-name-hint=[a-z_][a-z0-9_]{2,30}$
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
-# Regular expression matching correct constant names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-# Naming hint for constant names
-const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+[MISCELLANEOUS]
-# Regular expression matching correct attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
+# List of note tags to take in consideration, separated by a comma.
+notes=TODO
-# Naming hint for attribute names
-attr-name-hint=[a-z_][a-z0-9_]{2,30}$
-# Regular expression matching correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
+[STRING]
-# Naming hint for argument names
-argument-name-hint=[a-z_][a-z0-9_]{2,30}$
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=yes
-# Regular expression matching correct class attribute names
-class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-# Naming hint for class attribute names
-class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+[VARIABLES]
-# Regular expression matching correct inline iteration names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
-# Naming hint for inline iteration names
-inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
-# Regular expression matching correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
-# Naming hint for class names
-class-name-hint=[A-Z_][a-zA-Z0-9]+$
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
-# Regular expression matching correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
-# Naming hint for module names
-module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-# Regular expression matching correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
+[LOGGING]
-# Naming hint for method names
-method-name-hint=[a-z_][a-z0-9_]{2,30}$
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging,absl.logging,tensorflow.io.logging
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=__.*__
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
+[SIMILARITIES]
+# Minimum lines number of a similarity.
+min-similarity-lines=4
-[FORMAT]
+# Ignore comments when computing similarities.
+ignore-comments=yes
-# Maximum number of characters on a single line.
-max-line-length=80
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )??$
+# Ignore imports when computing similarities.
+ignore-imports=no
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-# List of optional constructs for which whitespace checking is disabled
-no-space-check=trailing-comma,dict-separator
+[SPELLING]
-# Maximum number of lines in a module
-max-module-lines=2000
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
-# Number of spaces of indent required inside a hanging or continued line.
-indent-after-paren=4
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,TERMIOS,Bastion,rexec
+deprecated-modules=regsub,
+ TERMIOS,
+ Bastion,
+ rexec,
+ sets
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
@@ -368,64 +363,37 @@ ext-import-graph=
# not be disabled)
int-import-graph=
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
-[CLASSES]
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant, absl
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=mcs
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
# List of member names, which should be excluded from the protected access
# warning.
-exclude-protected=_asdict,_fields,_replace,_source,_make
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=12
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=25
-
-# Maximum number of return / yield for function / method body
-max-returns=6
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
-# Maximum number of branch for function / method body
-max-branches=40
-
-# Maximum number of statements in function / method body
-max-statements=105
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=50
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
-
-# Python 2/3 compatibility
-disable=useless-object-inheritance
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls,
+ class_
-redefining-builtins-modules=oauth2client # Allow oauth2client to redefine file
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..4a9deaa4
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+ "recommendations": [
+ "google-workspace.google-workspace-developer-tools"
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 808c811a..6c65498b 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,11 @@ Perform mail merges from plain text or Google Sheets data sources
- [Quickstart](https://developers.google.com/drive/v3/web/quickstart/python)
- [DriveApp](drive/driveapp): A simple app that uploads a file to Google Drive.
+### Forms
+
+- [Quickstart](https://developers.google.com/forms/api/quickstart/python)
+- [Snippets](https://developers.google.com/forms/api/guides)
+
### Gmail
- [Quickstart](https://developers.google.com/gmail/api/quickstart/python)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..07bc436f
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,6 @@
+# Report a security issue
+
+To report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz). We use
+[https://g.co/vulnz](https://g.co/vulnz) for our intake, and do coordination and disclosure here on
+GitHub (including using GitHub Security Advisory). The Google Security Team will
+respond within 5 working days of your report on [https://g.co/vulnz](https://g.co/vulnz).
diff --git a/admin_sdk/directory/quickstart.py b/admin_sdk/directory/quickstart.py
index 074a545b..f4ba960f 100644
--- a/admin_sdk/directory/quickstart.py
+++ b/admin_sdk/directory/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START admin_sdk_directory_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -23,48 +21,51 @@
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']
+SCOPES = ["https://www.googleapis.com/auth/admin.directory.user"]
def main():
- """Shows basic usage of the Admin SDK Directory API.
- Prints the emails and names of the first 10 users in the domain.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Admin SDK Directory API.
+ Prints the emails and names of the first 10 users in the domain.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- service = build('admin', 'directory_v1', credentials=creds)
+ service = build("admin", "directory_v1", credentials=creds)
- # Call the Admin SDK Directory API
- print('Getting the first 10 users in the domain')
- results = service.users().list(customer='my_customer', maxResults=10,
- orderBy='email').execute()
- users = results.get('users', [])
+ # Call the Admin SDK Directory API
+ print("Getting the first 10 users in the domain")
+ results = (
+ service.users()
+ .list(customer="my_customer", maxResults=10, orderBy="email")
+ .execute()
+ )
+ users = results.get("users", [])
- if not users:
- print('No users in the domain.')
- else:
- print('Users:')
- for user in users:
- print(u'{0} ({1})'.format(user['primaryEmail'],
- user['name']['fullName']))
+ if not users:
+ print("No users in the domain.")
+ else:
+ print("Users:")
+ for user in users:
+ print(f"{user['primaryEmail']} ({user['name']['fullName']})")
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END admin_sdk_directory_quickstart]
diff --git a/admin_sdk/reports/quickstart.py b/admin_sdk/reports/quickstart.py
index d609abbd..cce9f415 100644
--- a/admin_sdk/reports/quickstart.py
+++ b/admin_sdk/reports/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START admin_sdk_reports_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -23,48 +21,57 @@
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/admin.reports.audit.readonly']
+SCOPES = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"]
def main():
- """Shows basic usage of the Admin SDK Reports API.
- Prints the time, email, and name of the last 10 login events in the domain.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Admin SDK Reports API.
+ Prints the time, email, and name of the last 10 login events in the domain.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- service = build('admin', 'reports_v1', credentials=creds)
+ service = build("admin", "reports_v1", credentials=creds)
- # Call the Admin SDK Reports API
- print('Getting the last 10 login events')
- results = service.activities().list(userKey='all', applicationName='login',
- maxResults=10).execute()
- activities = results.get('items', [])
+ # Call the Admin SDK Reports API
+ print("Getting the last 10 login events")
+ results = (
+ service.activities()
+ .list(userKey="all", applicationName="login", maxResults=10)
+ .execute()
+ )
+ activities = results.get("items", [])
- if not activities:
- print('No logins found.')
- else:
- print('Logins:')
- for activity in activities:
- print(u'{0}: {1} ({2})'.format(activity['id']['time'],
- activity['actor']['email'], activity['events'][0]['name']))
+ if not activities:
+ print("No logins found.")
+ else:
+ print("Logins:")
+ for activity in activities:
+ print(
+ "{0}: {1} ({2})".format(
+ activity["id"]["time"],
+ activity["actor"]["email"],
+ activity["events"][0]["name"],
+ )
+ )
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END admin_sdk_reports_quickstart]
diff --git a/admin_sdk/reseller/quickstart.py b/admin_sdk/reseller/quickstart.py
index 1e6133a3..cdcbd663 100644
--- a/admin_sdk/reseller/quickstart.py
+++ b/admin_sdk/reseller/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START admin_sdk_reseller_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -23,46 +21,52 @@
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/apps.order']
+SCOPES = ["https://www.googleapis.com/auth/apps.order"]
def main():
- """Calls the Admin SDK Reseller API. Prints the customer ID, SKU ID,
- and plan name of the first 10 subscriptions managed by the domain.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Calls the Admin SDK Reseller API. Prints the customer ID, SKU ID,
+ and plan name of the first 10 subscriptions managed by the domain.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- service = build('reseller', 'v1', credentials=creds)
+ service = build("reseller", "v1", credentials=creds)
- # Call the Admin SDK Reseller API
- print('Getting the first 10 subscriptions')
- results = service.subscriptions().list(maxResults=10).execute()
- subscriptions = results.get('subscriptions', [])
- if not subscriptions:
- print('No subscriptions found.')
- else:
- print('Subscriptions:')
- for subscription in subscriptions:
- print(u'{0} ({1}, {2})'.format(subscription['customerId'],
- subscription['skuId'], subscription['plan']['planName']))
+ # Call the Admin SDK Reseller API
+ print("Getting the first 10 subscriptions")
+ results = service.subscriptions().list(maxResults=10).execute()
+ subscriptions = results.get("subscriptions", [])
+ if not subscriptions:
+ print("No subscriptions found.")
+ else:
+ print("Subscriptions:")
+ for subscription in subscriptions:
+ print(
+ "{0} ({1}, {2})".format(
+ subscription["customerId"],
+ subscription["skuId"],
+ subscription["plan"]["planName"],
+ )
+ )
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END admin_sdk_reseller_quickstart]
diff --git a/apps_script/execute/execute.py b/apps_script/execute/execute.py
index 9d5e7fd7..3a0eabf3 100644
--- a/apps_script/execute/execute.py
+++ b/apps_script/execute/execute.py
@@ -1,86 +1,72 @@
-# Copyright Google Inc.
-#
-# 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.
+"""
+Copyright Google Inc.
-# [START apps_script_api_execute]
-from __future__ import print_function
+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
-from googleapiclient import errors
-from googleapiclient.discovery import build
-from oauth2client import client
-from oauth2client import file as oauth_file
-from oauth2client import tools
+ 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.
+"""
-def main():
- """Runs the sample.
- """
- SCRIPT_ID = 'ENTER_YOUR_SCRIPT_ID_HERE'
+# [START apps_script_api_execute]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
- # Set up the Apps Script API
- SCOPES = [
- 'https://www.googleapis.com/auth/script.scriptapp',
- 'https://www.googleapis.com/auth/drive.readonly',
- ]
- store = oauth_file.Storage('token.json')
- creds = store.get()
- if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
- creds = tools.run_flow(flow, store)
- service = build('script', 'v1', credentials=creds)
- # Create an execution request object.
- request = {"function": "getFoldersUnderRoot"}
+def main():
+ """Runs the sample."""
+ # pylint: disable=maybe-no-member
+ script_id = "1VFBDoJFy6yb9z7-luOwRv3fCmeNOzILPnR4QVmR0bGJ7gQ3QMPpCW-yt"
- try:
- # Make the API request.
- response = service.scripts().run(body=request,
- scriptId=SCRIPT_ID).execute()
+ creds, _ = google.auth.default()
+ service = build("script", "v1", credentials=creds)
- if 'error' in response:
- # The API executed, but the script returned an error.
+ # Create an execution request object.
+ request = {"function": "getFoldersUnderRoot"}
- # Extract the first (and only) set of error details. The values of
- # this object are the script's 'errorMessage' and 'errorType', and
- # an list of stack trace elements.
- error = response['error']['details'][0]
- print("Script error message: {0}".format(error['errorMessage']))
+ try:
+ # Make the API request.
+ response = service.scripts().run(scriptId=script_id, body=request).execute()
+ if "error" in response:
+ # The API executed, but the script returned an error.
+ # Extract the first (and only) set of error details. The values of
+ # this object are the script's 'errorMessage' and 'errorType', and
+ # a list of stack trace elements.
+ error = response["error"]["details"][0]
+ print(f"Script error message: {0}.{format(error['errorMessage'])}")
- if 'scriptStackTraceElements' in error:
- # There may not be a stacktrace if the script didn't start
- # executing.
- print("Script error stacktrace:")
- for trace in error['scriptStackTraceElements']:
- print("\t{0}: {1}".format(trace['function'],
- trace['lineNumber']))
- else:
- # The structure of the result depends upon what the Apps Script
- # function returns. Here, the function returns an Apps Script Object
- # with String keys and values, and so the result is treated as a
- # Python dictionary (folderSet).
- folderSet = response['response'].get('result', {})
- if not folderSet:
- print('No folders returned!')
- else:
- print('Folders under your root folder:')
- for (folderId, folder) in folderSet.items():
- print("\t{0} ({1})".format(folder, folderId))
+ if "scriptStackTraceElements" in error:
+ # There may not be a stacktrace if the script didn't start
+ # executing.
+ print("Script error stacktrace:")
+ for trace in error["scriptStackTraceElements"]:
+ print(f"\t{0}: {1}.{format(trace['function'], trace['lineNumber'])}")
+ else:
+ # The structure of the result depends upon what the Apps Script
+ # function returns. Here, the function returns an Apps Script
+ # Object with String keys and values, and so the result is
+ # treated as a Python dictionary (folder_set).
+ folder_set = response["response"].get("result", {})
+ if not folder_set:
+ print("No folders returned!")
+ else:
+ print("Folders under your root folder:")
+ for folder_id, folder in folder_set.items():
+ print(f"\t{0} ({1}).{format(folder, folder_id)}")
- except errors.HttpError as e:
- # The API encountered a problem before the script started executing.
- print(e.content)
+ except HttpError as error:
+ # The API encountered a problem before the script started executing.
+ print(f"An error occurred: {error}")
+ print(error.content)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END apps_script_api_execute]
diff --git a/apps_script/quickstart/quickstart.py b/apps_script/quickstart/quickstart.py
index 0718b449..e55aabb4 100644
--- a/apps_script/quickstart/quickstart.py
+++ b/apps_script/quickstart/quickstart.py
@@ -18,8 +18,6 @@
Call the Apps Script API to create a new script project, upload a file to the
project, and log the script's URL to the user.
"""
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -29,72 +27,73 @@
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/script.projects']
+SCOPES = ["https://www.googleapis.com/auth/script.projects"]
-SAMPLE_CODE = '''
+SAMPLE_CODE = """
function helloWorld() {
console.log("Hello, world!");
}
-'''.strip()
+""".strip()
-SAMPLE_MANIFEST = '''
+SAMPLE_MANIFEST = """
{
"timeZone": "America/New_York",
"exceptionLogging": "CLOUD"
}
-'''.strip()
+""".strip()
def main():
- """Calls the Apps Script API.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Calls the Apps Script API."""
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('script', 'v1', credentials=creds)
+ try:
+ service = build("script", "v1", credentials=creds)
- # Call the Apps Script API
- # Create a new project
- request = {'title': 'My Script'}
- response = service.projects().create(body=request).execute()
+ # Call the Apps Script API
+ # Create a new project
+ request = {"title": "My Script"}
+ response = service.projects().create(body=request).execute()
- # Upload two files to the project
- request = {
- 'files': [{
- 'name': 'hello',
- 'type': 'SERVER_JS',
- 'source': SAMPLE_CODE
- }, {
- 'name': 'appsscript',
- 'type': 'JSON',
- 'source': SAMPLE_MANIFEST
- }]
- }
- response = service.projects().updateContent(
- body=request,
- scriptId=response['scriptId']).execute()
- print('https://script.google.com/d/' + response['scriptId'] + '/edit')
- except errors.HttpError as error:
- # The API encountered a problem.
- print(error.content)
+ # Upload two files to the project
+ request = {
+ "files": [
+ {"name": "hello", "type": "SERVER_JS", "source": SAMPLE_CODE},
+ {
+ "name": "appsscript",
+ "type": "JSON",
+ "source": SAMPLE_MANIFEST,
+ },
+ ]
+ }
+ response = (
+ service.projects()
+ .updateContent(body=request, scriptId=response["scriptId"])
+ .execute()
+ )
+ print("https://script.google.com/d/" + response["scriptId"] + "/edit")
+ except errors.HttpError as error:
+ # The API encountered a problem.
+ print(error.content)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END apps_script_api_quickstart]
diff --git a/calendar/quickstart/quickstart.py b/calendar/quickstart/quickstart.py
index d3d827cf..18b94995 100644
--- a/calendar/quickstart/quickstart.py
+++ b/calendar/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START calendar_quickstart]
-from __future__ import print_function
-
import datetime
import os.path
@@ -25,55 +23,64 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
+SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
def main():
- """Shows basic usage of the Google Calendar API.
- Prints the start and name of the next 10 events on the user's calendar.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Google Calendar API.
+ Prints the start and name of the next 10 events on the user's calendar.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('calendar', 'v3', credentials=creds)
+ try:
+ service = build("calendar", "v3", credentials=creds)
- # Call the Calendar API
- now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
- print('Getting the upcoming 10 events')
- events_result = service.events().list(calendarId='primary', timeMin=now,
- maxResults=10, singleEvents=True,
- orderBy='startTime').execute()
- events = events_result.get('items', [])
+ # Call the Calendar API
+ now = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
+ print("Getting the upcoming 10 events")
+ events_result = (
+ service.events()
+ .list(
+ calendarId="primary",
+ timeMin=now,
+ maxResults=10,
+ singleEvents=True,
+ orderBy="startTime",
+ )
+ .execute()
+ )
+ events = events_result.get("items", [])
- if not events:
- print('No upcoming events found.')
- return
+ if not events:
+ print("No upcoming events found.")
+ return
- # Prints the start and name of the next 10 events
- for event in events:
- start = event['start'].get('dateTime', event['start'].get('date'))
- print(start, event['summary'])
+ # Prints the start and name of the next 10 events
+ for event in events:
+ start = event["start"].get("dateTime", event["start"].get("date"))
+ print(start, event["summary"])
- except HttpError as error:
- print('An error occurred: %s' % error)
+ except HttpError as error:
+ print(f"An error occurred: {error}")
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END calendar_quickstart]
diff --git a/chat/client-libraries/cloud/README.md b/chat/client-libraries/cloud/README.md
new file mode 100644
index 00000000..9fbdcfdf
--- /dev/null
+++ b/chat/client-libraries/cloud/README.md
@@ -0,0 +1,21 @@
+# Google Chat API - Cloud Client library samples
+
+## Set up
+
+1. Add `service_account.json` and/or `client_secrets.json` to the current
+ folder depending on the credentials used by the samples to run:
+
+ 1. `service_account.json` for
+ [app credentials](https://developers.google.com/workspace/chat/authenticate-authorize-chat-app)
+
+ 1. `client_secrets.json` for
+ [user credentials](https://developers.google.com/workspace/chat/authenticate-authorize-chat-user)
+
+1. Execute `pip install -r requirements.txt`
+
+## Run
+
+Execute `python replace-with-the-sample-file.py` wih the sample file path of the sample.
+
+For example, to run the sample `create-message-app-cred`, you should run
+`python create-message-app-cred.py`.
diff --git a/chat/client-libraries/cloud/authentication_utils.py b/chat/client-libraries/cloud/authentication_utils.py
new file mode 100644
index 00000000..d35ef798
--- /dev/null
+++ b/chat/client-libraries/cloud/authentication_utils.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_authentication_utils]
+import json
+
+import google.oauth2.credentials
+
+from google_auth_oauthlib.flow import InstalledAppFlow
+from google.apps import chat_v1 as google_chat
+
+CLIENT_SECRETS_FILE = 'client_secrets.json'
+
+SERVICE_ACCOUNT_FILE = 'service_account.json'
+
+APP_AUTH_OAUTH_SCOPE = ["https://www.googleapis.com/auth/chat.bot"]
+
+def create_client_with_app_credentials():
+ # For more information on app authentication, see
+ # https://developers.google.com/workspace/chat/authenticate-authorize-chat-app
+ creds = google.oauth2.service_account.Credentials.from_service_account_file(
+ SERVICE_ACCOUNT_FILE)
+
+ return google_chat.ChatServiceClient(
+ credentials = creds,
+ client_options={
+ "scopes": APP_AUTH_OAUTH_SCOPE
+ })
+
+def create_client_with_user_credentials(scopes):
+ # For more information on user authentication, see
+ # https://developers.google.com/workspace/chat/authenticate-authorize-chat-user
+ flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, scopes)
+ cred = flow.run_local_server()
+ installed = json.load(open(CLIENT_SECRETS_FILE))["installed"]
+
+ creds = google.oauth2.credentials.Credentials(
+ token = cred.token,
+ refresh_token = cred.refresh_token,
+ token_uri = installed["token_uri"],
+ client_id = installed["client_id"],
+ client_secret = installed["client_secret"],
+ scopes = scopes
+ )
+
+ # Create a client
+ client = google_chat.ChatServiceClient(
+ credentials = creds,
+ client_options = {
+ "scopes" : scopes
+ }
+ )
+
+ return client
+
+# [END chat_authentication_utils]
diff --git a/chat/client-libraries/cloud/create_membership_user_cred.py b/chat/client-libraries/cloud/create_membership_user_cred.py
new file mode 100644
index 00000000..fec4fc90
--- /dev/null
+++ b/chat/client-libraries/cloud/create_membership_user_cred.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_membership_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.memberships"]
+
+# This sample shows how to create membership with user credential for a human
+# user
+def create_membership_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMembershipRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ membership = {
+ "member": {
+ # Replace USER_NAME here
+ "name": "users/USER_NAME",
+ # user type for the membership
+ "type_": "HUMAN"
+ }
+ }
+ )
+
+ # Make the request
+ response = client.create_membership(request)
+
+ # Handle the response
+ print(response)
+
+create_membership_with_user_cred()
+
+# [END chat_create_membership_user_cred]
diff --git a/chat/client-libraries/cloud/create_membership_user_cred_for_app.py b/chat/client-libraries/cloud/create_membership_user_cred_for_app.py
new file mode 100644
index 00000000..57840f5c
--- /dev/null
+++ b/chat/client-libraries/cloud/create_membership_user_cred_for_app.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_create_membership_user_cred_for_app]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.memberships.app"]
+
+# This sample shows how to create membership with app credential for an app
+def create_membership_with_user_cred_for_app():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMembershipRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ membership = {
+ "member": {
+ # member name for app membership, do not change this.
+ "name": "users/app",
+ # user type for the membership
+ "type_": "BOT"
+ }
+ }
+ )
+
+ # Make the request
+ response = client.create_membership(request)
+
+ # Handle the response
+ print(response)
+
+create_membership_with_user_cred_for_app()
+
+# [END chat_create_membership_user_cred_for_app]
diff --git a/chat/client-libraries/cloud/create_membership_user_cred_for_group.py b/chat/client-libraries/cloud/create_membership_user_cred_for_group.py
new file mode 100644
index 00000000..fe90c4d3
--- /dev/null
+++ b/chat/client-libraries/cloud/create_membership_user_cred_for_group.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_membership_user_cred_for_group]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.memberships"]
+
+# This sample shows how to create membership with user credential for a group
+def create_membership_with_user_cred_for_group():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMembershipRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ membership = {
+ "groupMember": {
+ # Replace GROUP_NAME here
+ "name": "groups/GROUP_NAME"
+ }
+ }
+ )
+
+ # Make the request
+ response = client.create_membership(request)
+
+ # Handle the response
+ print(response)
+
+create_membership_with_user_cred_for_group()
+
+# [END chat_create_membership_user_cred_for_group]
diff --git a/chat/client-libraries/cloud/create_message_app_cred.py b/chat/client-libraries/cloud/create_message_app_cred.py
new file mode 100644
index 00000000..05db8d04
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_app_cred.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_create_message_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to create message with app credential
+def create_message_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here.
+ parent = "spaces/SPACE_NAME",
+ message = {
+ "text": '👋🌎 Hello world! I created this message by calling ' +
+ 'the Chat API\'s `messages.create()` method.',
+ "cards_v2" : [{ "card": {
+ "header": {
+ "title": 'About this message',
+ "image_url": 'https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/info/default/24px.svg'
+ },
+ "sections": [{
+ "header": "Contents",
+ "widgets": [{ "text_paragraph": {
+ "text": '🔡 Text which can include ' +
+ 'hyperlinks 🔗, emojis 😄🎉, and @mentions 🗣️.'
+ }}, { "text_paragraph": {
+ "text": '🖼️ A card to display visual elements' +
+ 'and request information such as text 🔤, ' +
+ 'dates and times 📅, and selections ☑️.'
+ }}, { "text_paragraph": {
+ "text": '👉🔘 An accessory widget which adds ' +
+ 'a button to the bottom of a message.'
+ }}
+ ]}, {
+ "header": "What's next",
+ "collapsible": True,
+ "widgets": [{ "text_paragraph": {
+ "text": "❤️ Add a reaction."
+ }}, { "text_paragraph": {
+ "text": "🔄 Update " +
+ "or ❌ delete " +
+ "the message."
+ }
+ }]
+ }
+ ]
+ }}],
+ "accessory_widgets": [{ "button_list": { "buttons": [{
+ "text": 'View documentation',
+ "icon": { "material_icon": { "name": 'link' }},
+ "on_click": { "open_link": {
+ "url": 'https://developers.google.com/workspace/chat/create-messages'
+ }}
+ }]}}]
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_app_cred()
+
+# [END chat_create_message_app_cred]
diff --git a/chat/client-libraries/cloud/create_message_user_cred.py b/chat/client-libraries/cloud/create_message_user_cred.py
new file mode 100644
index 00000000..a697b97e
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_create_message_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+def create_message_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here.
+ parent = "spaces/SPACE_NAME",
+ message = {
+ "text": '👋🌎 Hello world!' +
+ 'Text messages can contain things like:\n\n' +
+ '* Hyperlinks 🔗\n' +
+ '* Emojis 😄🎉\n' +
+ '* Mentions of other Chat users `@` \n\n' +
+ 'For details, see the ' +
+ '.'
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred()
+
+# [END chat_create_message_user_cred]
diff --git a/chat/client-libraries/cloud/create_message_user_cred_at_mention.py b/chat/client-libraries/cloud/create_message_user_cred_at_mention.py
new file mode 100644
index 00000000..6dde1344
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred_at_mention.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_message_user_cred_at_mention]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+# This sample shows how to create message with user credential with at mention
+def create_message_with_user_cred_at_mention():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ message = {
+ # The user with USER_NAME will be at mentioned if they are in the
+ # space.
+ # Replace USER_NAME here
+ "text": "Hello !"
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred_at_mention()
+
+# [END chat_create_message_user_cred_at_mention]
diff --git a/chat/client-libraries/cloud/create_message_user_cred_message_id.py b/chat/client-libraries/cloud/create_message_user_cred_message_id.py
new file mode 100644
index 00000000..6e52cde5
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred_message_id.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_message_user_cred_message_id]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+# This sample shows how to create message with user credential with message id
+def create_message_with_user_cred_message_id():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ # Message id let chat apps get, update or delete a message without needing
+ # to store the system assigned ID in the message's resource name.
+ message_id = "client-MESSAGE-ID",
+ message = {
+ "text": "Hello with user credential!"
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred_message_id()
+
+# [END chat_create_message_user_cred_message_id]
diff --git a/chat/client-libraries/cloud/create_message_user_cred_request_id.py b/chat/client-libraries/cloud/create_message_user_cred_request_id.py
new file mode 100644
index 00000000..58c67b25
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred_request_id.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_message_user_cred_request_id]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+# This sample shows how to create message with user credential with request id
+def create_message_with_user_cred_request_id():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ # Specifying an existing request ID returns the message created with
+ # that ID instead of creating a new message.
+ request_id = "REQUEST_ID",
+ message = {
+ "text": "Hello with user credential!"
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred_request_id()
+
+# [END chat_create_message_user_cred_request_id]
diff --git a/chat/client-libraries/cloud/create_message_user_cred_thread_key.py b/chat/client-libraries/cloud/create_message_user_cred_thread_key.py
new file mode 100644
index 00000000..75cda5f1
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred_thread_key.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_create_message_user_cred_thread_key]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+import google.apps.chat_v1.CreateMessageRequest.MessageReplyOption
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+# This sample shows how to create message with user credential with thread key
+def create_message_with_user_cred_thread_key():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ # Creates the message as a reply to the thread specified by thread_key.
+ # If it fails, the message starts a new thread instead.
+ message_reply_option = MessageReplyOption.REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD,
+ message = {
+ "text": "Hello with user credential!",
+ "thread": {
+ # Thread key specifies a thread and is unique to the chat app
+ # that sets it.
+ "thread_key": "THREAD_KEY"
+ }
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred_thread_key()
+
+# [END chat_create_message_user_cred_thread_key]
diff --git a/chat/client-libraries/cloud/create_message_user_cred_thread_name.py b/chat/client-libraries/cloud/create_message_user_cred_thread_name.py
new file mode 100644
index 00000000..c608261e
--- /dev/null
+++ b/chat/client-libraries/cloud/create_message_user_cred_thread_name.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_create_message_user_cred_thread_name]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+import google.apps.chat_v1.CreateMessageRequest.MessageReplyOption
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.create"]
+
+# This sample shows how to create message with user credential with thread name
+def create_message_with_user_cred_thread_name():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateMessageRequest(
+ # Replace SPACE_NAME here
+ parent = "spaces/SPACE_NAME",
+ # Creates the message as a reply to the thread specified by thread.name.
+ # If it fails, the message starts a new thread instead.
+ message_reply_option = MessageReplyOption.REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD,
+ message = {
+ "text": "Hello with user credential!",
+ "thread": {
+ # Resource name of a thread that uniquely identify a thread.
+ # Replace SPACE_NAME and THREAD_NAME here
+ "name": "spaces/SPACE_NAME/threads/THREAD_NAME"
+ }
+ }
+ )
+
+ # Make the request
+ response = client.create_message(request)
+
+ # Handle the response
+ print(response)
+
+create_message_with_user_cred_thread_name()
+
+# [END chat_create_message_user_cred_thread_name]
diff --git a/chat/client-libraries/cloud/create_space_user_cred.py b/chat/client-libraries/cloud/create_space_user_cred.py
new file mode 100644
index 00000000..7ff01d45
--- /dev/null
+++ b/chat/client-libraries/cloud/create_space_user_cred.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_create_space_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.spaces.create"]
+
+def create_space_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.CreateSpaceRequest(
+ space = {
+ "space_type": 'SPACE',
+ # Replace DISPLAY_NAME here.
+ "display_name": 'DISPLAY_NAME'
+ }
+ )
+
+ # Make the request
+ response = client.create_space(request)
+
+ # Handle the response
+ print(response)
+
+create_space_with_user_cred()
+
+# [END chat_create_space_user_cred]
diff --git a/chat/client-libraries/cloud/delete_message_app_cred.py b/chat/client-libraries/cloud/delete_message_app_cred.py
new file mode 100644
index 00000000..a4706255
--- /dev/null
+++ b/chat/client-libraries/cloud/delete_message_app_cred.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_delete_message_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to delete a message with app credential
+def delete_message_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.DeleteMessageRequest(
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ name = "spaces/SPACE_NAME/messages/MESSAGE_NAME",
+ )
+
+ # Make the request
+ response = client.delete_message(request)
+
+ # Handle the response
+ print(response)
+
+delete_message_with_app_cred()
+
+# [END chat_delete_message_app_cred]
diff --git a/chat/client-libraries/cloud/delete_message_user_cred.py b/chat/client-libraries/cloud/delete_message_user_cred.py
new file mode 100644
index 00000000..d8a046a2
--- /dev/null
+++ b/chat/client-libraries/cloud/delete_message_user_cred.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_delete_message_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages"]
+
+# This sample shows how to delete a message with user credential
+def delete_message_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.DeleteMessageRequest(
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ name = "spaces/SPACE_NAME/messages/MESSAGE_NAME",
+ )
+
+ # Make the request
+ response = client.delete_message(request)
+
+ # Handle the response
+ print(response)
+
+delete_message_with_user_cred()
+
+# [END chat_delete_message_user_cred]
diff --git a/chat/client-libraries/cloud/get_membership_app_cred.py b/chat/client-libraries/cloud/get_membership_app_cred.py
new file mode 100644
index 00000000..12325a1d
--- /dev/null
+++ b/chat/client-libraries/cloud/get_membership_app_cred.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_membership_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to get membership with app credential
+def get_membership_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.GetMembershipRequest(
+ # Replace SPACE_NAME and MEMBER_NAME here
+ name = 'spaces/SPACE_NAME/members/MEMBER_NAME',
+ )
+
+ # Make the request
+ response = client.get_membership(request)
+
+ # Handle the response
+ print(response)
+
+get_membership_with_app_cred()
+
+# [END chat_get_membership_app_cred]
diff --git a/chat/client-libraries/cloud/get_membership_user_cred.py b/chat/client-libraries/cloud/get_membership_user_cred.py
new file mode 100644
index 00000000..bab553a4
--- /dev/null
+++ b/chat/client-libraries/cloud/get_membership_user_cred.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_membership_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.memberships.readonly"]
+
+# This sample shows how to get membership with user credential
+def get_membership_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.GetMembershipRequest(
+ # Replace SPACE_NAME and MEMBER_NAME here
+ name = 'spaces/SPACE_NAME/members/MEMBER_NAME',
+ )
+
+ # Make the request
+ response = client.get_membership(request)
+
+ # Handle the response
+ print(response)
+
+get_membership_with_user_cred()
+
+# [END chat_get_membership_user_cred]
diff --git a/chat/client-libraries/cloud/get_message_app_cred.py b/chat/client-libraries/cloud/get_message_app_cred.py
new file mode 100644
index 00000000..ca8e7888
--- /dev/null
+++ b/chat/client-libraries/cloud/get_message_app_cred.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_message_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to get message with app credential
+def get_message_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.GetMessageRequest(
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ name = 'spaces/SPACE_NAME/messages/MESSAGE_NAME',
+ )
+
+ # Make the request
+ response = client.get_message(request=request)
+
+ # Handle the response
+ print(response)
+
+get_message_with_app_cred()
+
+# [END chat_get_message_app_cred]
diff --git a/chat/client-libraries/cloud/get_message_user_cred.py b/chat/client-libraries/cloud/get_message_user_cred.py
new file mode 100644
index 00000000..8f160b35
--- /dev/null
+++ b/chat/client-libraries/cloud/get_message_user_cred.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_message_user_cred]
+from authentication_utils import create_client_with_user_credentials
+import google.oauth2.credentials
+
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.readonly"]
+
+# This sample shows how to get message with user credential
+def get_message_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.GetMessageRequest(
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ name = "spaces/SPACE_NAME/messages/MESSAGE_NAME",
+ )
+
+ # Make the request
+ response = client.get_message(request)
+
+ # Handle the response
+ print(response)
+
+get_message_with_user_cred()
+
+# [END chat_get_message_user_cred]
diff --git a/chat/client-libraries/cloud/get_space_app_cred.py b/chat/client-libraries/cloud/get_space_app_cred.py
new file mode 100644
index 00000000..1f5bb341
--- /dev/null
+++ b/chat/client-libraries/cloud/get_space_app_cred.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_space_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to get space with app credential
+def get_space_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.GetSpaceRequest(
+ # Replace SPACE_NAME here
+ name = "spaces/SPACE_NAME",
+ )
+
+ # Make the request
+ response = client.get_space(request)
+
+ # Handle the response
+ print(response)
+
+get_space_with_app_cred()
+
+# [END chat_get_space_app_cred]
diff --git a/chat/client-libraries/cloud/get_space_user_cred.py b/chat/client-libraries/cloud/get_space_user_cred.py
new file mode 100644
index 00000000..3287762d
--- /dev/null
+++ b/chat/client-libraries/cloud/get_space_user_cred.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Snippet for GetSpace
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_get_space_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.spaces.readonly"]
+
+# This sample shows how to get space with user credential
+def get_space_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.GetSpaceRequest(
+ # Replace SPACE_NAME here
+ name = "spaces/SPACE_NAME",
+ )
+
+ # Make the request
+ response = client.get_space(request)
+
+ # Handle the response
+ print(response)
+
+get_space_with_user_cred()
+
+# [END chat_get_space_user_cred]
diff --git a/chat/client-libraries/cloud/list_memberships_app_cred.py b/chat/client-libraries/cloud/list_memberships_app_cred.py
new file mode 100644
index 00000000..6ebe1eb3
--- /dev/null
+++ b/chat/client-libraries/cloud/list_memberships_app_cred.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_list_memberships_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to list memberships with app credential
+def list_memberships_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.ListMembershipsRequest(
+ # Replace SPACE_NAME here
+ parent = 'spaces/SPACE_NAME',
+ # Filter membership by type (HUMAN or BOT) or role (ROLE_MEMBER or
+ # ROLE_MANAGER)
+ filter = 'member.type = "HUMAN"',
+ # Number of results that will be returned at once
+ page_size = 100
+ )
+
+ # Make the request
+ page_result = client.list_memberships(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+
+list_memberships_app_cred()
+
+# [END chat_list_memberships_app_cred]
diff --git a/chat/client-libraries/cloud/list_memberships_user_cred.py b/chat/client-libraries/cloud/list_memberships_user_cred.py
new file mode 100644
index 00000000..4d50c959
--- /dev/null
+++ b/chat/client-libraries/cloud/list_memberships_user_cred.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_list_memberships_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.memberships.readonly"]
+
+# This sample shows how to list memberships with user credential
+def list_memberships_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.ListMembershipsRequest(
+ # Replace SPACE_NAME here
+ parent = 'spaces/SPACE_NAME',
+ # Filter membership by type (HUMAN or BOT) or role (ROLE_MEMBER or
+ # ROLE_MANAGER)
+ filter = 'member.type = "HUMAN"',
+ # Number of results that will be returned at once
+ page_size = 100
+ )
+
+ # Make the request
+ page_result = client.list_memberships(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+
+list_memberships_user_cred()
+
+# [END chat_list_memberships_user_cred]
diff --git a/chat/client-libraries/cloud/list_messages_user_cred.py b/chat/client-libraries/cloud/list_messages_user_cred.py
new file mode 100644
index 00000000..cacef343
--- /dev/null
+++ b/chat/client-libraries/cloud/list_messages_user_cred.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_list_messages_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages.readonly"]
+
+# This sample shows how to list messages with user credential
+def list_messages_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.ListMessagesRequest(
+ # Replace SPACE_NAME here
+ parent = 'spaces/SPACE_NAME',
+ # Number of results that will be returned at once
+ page_size = 100
+ )
+
+ # Make the request
+ page_result = client.list_messages(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+
+list_messages_with_user_cred()
+
+# [END chat_list_messages_user_cred]
diff --git a/chat/client-libraries/cloud/list_spaces_app_cred.py b/chat/client-libraries/cloud/list_spaces_app_cred.py
new file mode 100644
index 00000000..0c41ae20
--- /dev/null
+++ b/chat/client-libraries/cloud/list_spaces_app_cred.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_list_spaces_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to list spaces with app credential
+def list_spaces_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.ListSpacesRequest(
+ # Filter spaces by space type (SPACE or GROUP_CHAT or DIRECT_MESSAGE)
+ filter = 'space_type = "SPACE"',
+ # Number of results that will be returned at once
+ page_size = 100
+ )
+
+ # Make the request
+ page_result = client.list_spaces(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+
+list_spaces_app_cred()
+
+# [END chat_list_spaces_app_cred]
diff --git a/chat/client-libraries/cloud/list_spaces_user_cred.py b/chat/client-libraries/cloud/list_spaces_user_cred.py
new file mode 100644
index 00000000..5ae906cf
--- /dev/null
+++ b/chat/client-libraries/cloud/list_spaces_user_cred.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_list_spaces_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.spaces.readonly"]
+
+# This sample shows how to list spaces with user credential
+def list_spaces_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.ListSpacesRequest(
+ # Filter spaces by space type (SPACE or GROUP_CHAT or DIRECT_MESSAGE)
+ filter = 'space_type = "SPACE"',
+ # Number of results that will be returned at once
+ page_size = 100
+ )
+
+ # Make the request
+ page_result = client.list_spaces(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+
+list_spaces_with_user_cred()
+
+# [END chat_list_spaces_user_cred]
diff --git a/chat/client-libraries/cloud/requirements.txt b/chat/client-libraries/cloud/requirements.txt
new file mode 100644
index 00000000..bf63a182
--- /dev/null
+++ b/chat/client-libraries/cloud/requirements.txt
@@ -0,0 +1,3 @@
+google_auth_oauthlib==1.2.0
+protobuf==4.21.12
+google-apps-chat==0.1.9
diff --git a/chat/client-libraries/cloud/set_up_space_user_cred.py b/chat/client-libraries/cloud/set_up_space_user_cred.py
new file mode 100644
index 00000000..da20fc80
--- /dev/null
+++ b/chat/client-libraries/cloud/set_up_space_user_cred.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_set_up_space_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.spaces.create"]
+
+def set_up_space_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.SetUpSpaceRequest(
+ space = {
+ "space_type": 'SPACE',
+ # Replace DISPLAY_NAME here.
+ "display_name": 'DISPLAY_NAME'
+ },
+ memberships = [{
+ "member": {
+ # Replace USER_NAME here.
+ "name": 'users/USER_NAME',
+ "type_": 'HUMAN'
+ }
+ }]
+ )
+
+ # Make the request
+ response = client.set_up_space(request)
+
+ # Handle the response
+ print(response)
+
+set_up_space_with_user_cred()
+
+# [END chat_set_up_space_user_cred]
diff --git a/chat/client-libraries/cloud/update_message_app_cred.py b/chat/client-libraries/cloud/update_message_app_cred.py
new file mode 100644
index 00000000..40dda760
--- /dev/null
+++ b/chat/client-libraries/cloud/update_message_app_cred.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+# [START chat_update_message_app_cred]
+from authentication_utils import create_client_with_app_credentials
+from google.apps import chat_v1 as google_chat
+
+# This sample shows how to update a message with app credential
+def update_message_with_app_cred():
+ # Create a client
+ client = create_client_with_app_credentials()
+
+ # Initialize request argument(s)
+ request = google_chat.UpdateMessageRequest(
+ message = {
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ "name": "spaces/SPACE_NAME/messages/MESSAGE_NAME",
+ "text": "Text updated with app credential!",
+ "cards_v2" : [{ "card": { "header": {
+ "title": 'Card updated with app credential!',
+ "image_url": 'https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/info/default/24px.svg'
+ }}}]
+ },
+ # The field paths to update. Separate multiple values with commas or use
+ # `*` to update all field paths.
+ update_mask = "text,cardsV2"
+ )
+
+ # Make the request
+ response = client.update_message(request)
+
+ # Handle the response
+ print(response)
+
+update_message_with_app_cred()
+
+# [END chat_update_message_app_cred]
diff --git a/chat/client-libraries/cloud/update_message_user_cred.py b/chat/client-libraries/cloud/update_message_user_cred.py
new file mode 100644
index 00000000..18146e3d
--- /dev/null
+++ b/chat/client-libraries/cloud/update_message_user_cred.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_update_message_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.messages"]
+
+# This sample shows how to update a message with user credential
+def update_message_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.UpdateMessageRequest(
+ message = {
+ # Replace SPACE_NAME and MESSAGE_NAME here
+ "name": "spaces/SPACE_NAME/messages/MESSAGE_NAME",
+ "text": "Updated with user credential!"
+ },
+ # The field paths to update. Separate multiple values with commas or use
+ # `*` to update all field paths.
+ update_mask = "text"
+ )
+
+ # Make the request
+ response = client.update_message(request)
+
+ # Handle the response
+ print(response)
+
+update_message_with_user_cred()
+
+# [END chat_update_message_user_cred]
diff --git a/chat/client-libraries/cloud/update_space_user_cred.py b/chat/client-libraries/cloud/update_space_user_cred.py
new file mode 100644
index 00000000..6c3540a6
--- /dev/null
+++ b/chat/client-libraries/cloud/update_space_user_cred.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# It may require modifications to work in your environment.
+
+# To install the latest published package dependency, execute the following:
+# python3 -m pip install google-apps-chat
+
+
+# [START chat_update_space_user_cred]
+from authentication_utils import create_client_with_user_credentials
+from google.apps import chat_v1 as google_chat
+
+SCOPES = ["https://www.googleapis.com/auth/chat.spaces"]
+
+# This sample shows how to update a space with user credential
+def update_space_with_user_cred():
+ # Create a client
+ client = create_client_with_user_credentials(SCOPES)
+
+ # Initialize request argument(s)
+ request = google_chat.UpdateSpaceRequest(
+ space = {
+ # Replace SPACE_NAME here
+ 'name': 'spaces/SPACE_NAME',
+ 'display_name': 'New space display name'
+ },
+ # The field paths to update. Separate multiple values with commas.
+ update_mask = 'displayName'
+ )
+
+ # Make the request
+ response = client.update_space(request)
+
+ # Handle the response
+ print(response)
+
+update_space_with_user_cred()
+
+# [END chat_update_space_user_cred]
diff --git a/chat/quickstart/README.md b/chat/quickstart/README.md
new file mode 100644
index 00000000..ef44f9c8
--- /dev/null
+++ b/chat/quickstart/README.md
@@ -0,0 +1,16 @@
+# Google Chat Python Quickstart
+
+Complete the steps described in the [quickstart instructions](
+https://developers.google.com/workspace/chat/api/guides/quickstart/python),
+and in about five minutes you'll have a simple Python command-line
+application that makes requests to the Google Chat API.
+
+## Install
+
+`pip install -r requirements`
+
+## Run
+
+After following the quickstart setup instructions, run the sample:
+
+`python3 quickstart.py`
diff --git a/chat/quickstart/quickstart.py b/chat/quickstart/quickstart.py
new file mode 100644
index 00000000..a29c6836
--- /dev/null
+++ b/chat/quickstart/quickstart.py
@@ -0,0 +1,80 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# [START chat_quickstart]
+from __future__ import print_function
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from google.apps import chat_v1 as google_chat
+
+
+# If modifying these scopes, delete the file token.json.
+SCOPES = ['https://www.googleapis.com/auth/chat.spaces.readonly']
+
+
+def main():
+ """Shows basic usage of the Google Chat API.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists('token.json'):
+ creds = Credentials.from_authorized_user_file('token.json', SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ 'credentials.json', SCOPES)
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open('token.json', 'w') as token:
+ token.write(creds.to_json())
+
+ try:
+ # Create a client
+ client = google_chat.ChatServiceClient(
+ credentials = creds,
+ client_options = {
+ "scopes" : SCOPES
+ }
+ )
+
+ # Initialize request argument(s)
+ request = google_chat.ListSpacesRequest(
+ # Filter spaces by space type (SPACE or GROUP_CHAT or DIRECT_MESSAGE)
+ filter = 'space_type = "SPACE"'
+ )
+
+ # Make the request
+ page_result = client.list_spaces(request)
+
+ # Handle the response. Iterating over page_result will yield results and
+ # resolve additional pages automatically.
+ for response in page_result:
+ print(response)
+ except Exception as error:
+ # TODO(developer) - Handle errors from Chat API.
+ print(f'An error occurred: {error}')
+
+
+if __name__ == '__main__':
+ main()
+# [END chat_quickstart]
diff --git a/chat/quickstart/requirements.txt b/chat/quickstart/requirements.txt
new file mode 100644
index 00000000..aeabc164
--- /dev/null
+++ b/chat/quickstart/requirements.txt
@@ -0,0 +1,3 @@
+google-apps-chat==0.1.0
+google-auth-httplib2==0.1.0
+google-auth-oauthlib==0.4.0
diff --git a/classroom/quickstart/quickstart.py b/classroom/quickstart/quickstart.py
index 9f1d65e9..3708c0a2 100644
--- a/classroom/quickstart/quickstart.py
+++ b/classroom/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START classroom_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,50 +22,51 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/classroom.courses.readonly']
+SCOPES = ["https://www.googleapis.com/auth/classroom.courses.readonly"]
def main():
- """Shows basic usage of the Classroom API.
- Prints the names of the first 10 courses the user has access to.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Classroom API.
+ Prints the names of the first 10 courses the user has access to.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('classroom', 'v1', credentials=creds)
+ try:
+ service = build("classroom", "v1", credentials=creds)
- # Call the Classroom API
- results = service.courses().list(pageSize=10).execute()
- courses = results.get('courses', [])
+ # Call the Classroom API
+ results = service.courses().list(pageSize=10).execute()
+ courses = results.get("courses", [])
- if not courses:
- print('No courses found.')
- return
- # Prints the names of the first 10 courses.
- print('Courses:')
- for course in courses:
- print(course['name'])
+ if not courses:
+ print("No courses found.")
+ return
+ # Prints the names of the first 10 courses.
+ print("Courses:")
+ for course in courses:
+ print(course["name"])
- except HttpError as error:
- print('An error occurred: %s' % error)
+ except HttpError as error:
+ print(f"An error occurred: {error}")
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END classroom_quickstart]
diff --git a/classroom/snippets/base_test.py b/classroom/snippets/base_test.py
index a241f644..34432364 100644
--- a/classroom/snippets/base_test.py
+++ b/classroom/snippets/base_test.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import print_function
-
import sys
import unittest
@@ -22,44 +20,45 @@
from googleapiclient.discovery import build
from oauth2client.client import GoogleCredentials
-SCOPES = 'https://www.googleapis.com/auth/classroom.courses'
+SCOPES = "https://www.googleapis.com/auth/classroom.courses"
class BaseTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.credentials = cls.create_credentials()
- http = cls.credentials.authorize(httplib2.Http())
- cls.credentials.refresh(http)
- cls.service = build('classroom', 'v1', http=http)
- cls.stdout = sys.stdout
- sys.stdout = None
- @classmethod
- def tearDownClass(cls):
- # Restore STDOUT.
- sys.stdout = cls.stdout
+ @classmethod
+ def setUpClass(cls):
+ cls.credentials = cls.create_credentials()
+ http = cls.credentials.authorize(httplib2.Http())
+ cls.credentials.refresh(http)
+ cls.service = build("classroom", "v1", http=http)
+ cls.stdout = sys.stdout
+ sys.stdout = None
+
+ @classmethod
+ def tearDownClass(cls):
+ # Restore STDOUT.
+ sys.stdout = cls.stdout
- @classmethod
- def create_credentials(cls):
- cls.credentials = GoogleCredentials.get_application_default()
- scope = ['https://www.googleapis.com/auth/drive']
- return cls.credentials.create_scoped(scope)
+ @classmethod
+ def create_credentials(cls):
+ cls.credentials = GoogleCredentials.get_application_default()
+ scope = ["https://www.googleapis.com/auth/drive"]
+ return cls.credentials.create_scoped(scope)
- def setUp(self):
- self.courses_to_delete = []
- print("Meow" + str(self.courses_to_delete))
+ def setUp(self):
+ self.courses_to_delete = []
+ print("Meow" + str(self.courses_to_delete))
- def tearDown(self):
- for course_id in self.courses_to_delete:
- try:
- self.service.courses().delete(id=course_id).execute()
- except errors.HttpError:
- print('Unable to delete file %s' % course_id)
+ def tearDown(self):
+ for course_id in self.courses_to_delete:
+ try:
+ self.service.courses().delete(id=course_id).execute()
+ except errors.HttpError:
+ print(f"Unable to delete file {course_id}")
- def delete_course_on_cleanup(self, course_id):
- self.courses_to_delete.append(course_id)
+ def delete_course_on_cleanup(self, course_id):
+ self.courses_to_delete.append(course_id)
-if __name__ == '__main__':
- unittest.main()
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/classroom_add_alias_existing.py b/classroom/snippets/classroom_add_alias_existing.py
new file mode 100644
index 00000000..cb777291
--- /dev/null
+++ b/classroom/snippets/classroom_add_alias_existing.py
@@ -0,0 +1,54 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+# [START classroom_add_alias_existing]
+def classroom_add_alias_existing(course_id):
+ """
+ Adds alias to existing course with specific course_id.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ # [START classroom_existing_alias]
+ service = build("classroom", "v1", credentials=creds)
+ alias = "d:school_math_101"
+ course_alias = {"alias": alias}
+ try:
+ course_alias = (
+ service.courses()
+ .aliases()
+ .create(courseId=course_id, body=course_alias)
+ .execute()
+ )
+ return course_alias
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Alias Creation Failed")
+ return course_alias
+ # [END classroom_existing_alias]
+
+
+if __name__ == "__main__":
+ # Put the course_id of course whose alias needs to be added.
+ classroom_add_alias_existing(456058313539)
+
+# [END classroom_existing_alias]
diff --git a/classroom/snippets/classroom_add_alias_new.py b/classroom/snippets/classroom_add_alias_new.py
new file mode 100644
index 00000000..65253653
--- /dev/null
+++ b/classroom/snippets/classroom_add_alias_new.py
@@ -0,0 +1,81 @@
+"""
+Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+# [START classroom_new_alias]
+SCOPES = ["https://www.googleapis.com/auth/classroom.courses"]
+
+
+def classroom_add_alias_new():
+ """
+ Creates a course with alias specification the user has access to.
+ The file token.json stores the user's access and refresh tokens, and is
+ created automatically when the authorization flow completes for
+ the first time.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity for
+ guides on implementing OAuth2 for the application.
+ """
+ # pylint: disable=maybe-no-member
+ creds = None
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w", encoding="utf8") as token:
+ token.write(creds.to_json())
+
+ alias = "d:school_physics_333"
+ course = {
+ "id": alias,
+ "name": "English",
+ "section": "Period 2",
+ "description": "Course Description",
+ "room": "301",
+ "ownerId": "me",
+ }
+ try:
+ print("-------------")
+ service = build("classroom", "v1", credentials=creds)
+ course = service.courses().create(body=course).execute()
+ print("====================================")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return course
+
+
+if __name__ == "__main__":
+ # pylint: disable=too-many-arguments
+ # Put the course_id of course whose alias needs to be created.
+ classroom_add_alias_new()
+
+# [END classroom_new_alias]
diff --git a/classroom/snippets/classroom_add_attachment.py b/classroom/snippets/classroom_add_attachment.py
new file mode 100644
index 00000000..e65dfabb
--- /dev/null
+++ b/classroom/snippets/classroom_add_attachment.py
@@ -0,0 +1,58 @@
+"""
+Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+# [START classroom_add_attachment]
+def classroom_add_attachment(course_id, coursework_id, submission_id):
+ """
+ Adds attachment to existing course with specific course_id.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ request = {
+ "addAttachments": [
+ {"link": {"url": "http://example.com/quiz-results"}},
+ {"link": {"url": "http://example.com/quiz-reading"}},
+ ]
+ }
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ while True:
+ coursework = service.courses().courseWork()
+ coursework.studentSubmissions().modifyAttachments(
+ courseId=course_id,
+ courseWorkId=coursework_id,
+ id=submission_id,
+ body=request,
+ ).execute()
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ # Put the course_id, coursework_id and submission_id of course in which
+ # attachment needs to be added.
+ classroom_add_attachment("course_id", "coursework_id", "me")
+# [END classroom_add_attachment]
diff --git a/classroom/snippets/classroom_add_student.py b/classroom/snippets/classroom_add_student.py
new file mode 100644
index 00000000..3f7ee5f7
--- /dev/null
+++ b/classroom/snippets/classroom_add_student.py
@@ -0,0 +1,83 @@
+"""Copyright 2022 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."""
+
+# [START classroom_add_student]
+import os
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+SCOPES = ["https://www.googleapis.com/auth/classroom.coursework.students"]
+
+
+def classroom_add_student_new(course_id):
+ """
+ Adds a student to a course, the teacher has access to.
+ The file token.json stores the user's access and refresh tokens, and is
+ created automatically when the authorization flow completes for the first
+ time.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity for
+ guides on implementing OAuth2 for the application.
+ """
+
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w", encoding="utf8") as token:
+ token.write(creds.to_json())
+
+ enrollment_code = "abc-def"
+ student = {"userId": "gduser1@workspacesamples.dev"}
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ student = (
+ service.courses()
+ .students()
+ .create(
+ courseId=course_id, enrollmentCode=enrollment_code, body=student
+ )
+ .execute()
+ )
+ print(
+ '''User {%s} was enrolled as a student in
+ the course with ID "{%s}"'''
+ % (student.get("profile").get("name").get("fullName"), course_id)
+ )
+ return student
+ except HttpError as error:
+ print(error)
+ return error
+
+
+if __name__ == "__main__":
+ # Put the course_id of course for which student needs to be added.
+ classroom_add_student_new(478800920837)
+# [END classroom_add_student]
diff --git a/classroom/snippets/classroom_add_teacher.py b/classroom/snippets/classroom_add_teacher.py
new file mode 100644
index 00000000..9b86b715
--- /dev/null
+++ b/classroom/snippets/classroom_add_teacher.py
@@ -0,0 +1,51 @@
+"""Copyright 2022 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."""
+
+# [START classroom_add_teacher]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_add_teacher(course_id):
+ """
+ Adds a teacher to a course with specific course_id.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ service = build("classroom", "v1", credentials=creds)
+
+ teacher_email = "gduser1@workspacesamples.dev"
+ teacher = {"userId": teacher_email}
+
+ try:
+ teachers = service.courses().teachers()
+ teacher = teachers.create(courseId=course_id, body=teacher).execute()
+ print(
+ "User %s was added as a teacher to the course with ID %s"
+ % (teacher.get("profile").get("name").get("fullName"), course_id)
+ )
+ except HttpError as error:
+ print('User "{%s}" is already a member of this course.' % teacher_email)
+ return error
+ return teachers
+
+
+if __name__ == "__main__":
+ # Put the course_id of course for which Teacher needs to be added.
+ classroom_add_teacher(453686957652)
+# [END classroom_add_teacher]
diff --git a/classroom/snippets/classroom_all_submissions.py b/classroom/snippets/classroom_all_submissions.py
new file mode 100644
index 00000000..1c505fc2
--- /dev/null
+++ b/classroom/snippets/classroom_all_submissions.py
@@ -0,0 +1,75 @@
+"""
+Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+# [START classroom_all_submissions]
+def classroom_all_submissions(course_id, user_id):
+ """
+ Creates the list of all submissions of the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ submissions = []
+ page_token = None
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ while True:
+ coursework = service.courses().courseWork()
+ response = (
+ coursework.studentSubmissions()
+ .list(
+ pageToken=page_token,
+ courseId=course_id,
+ courseWorkId="-",
+ userId=user_id,
+ )
+ .execute()
+ )
+ submissions.extend(response.get("studentSubmissions", []))
+ page_token = response.get("nextPageToken", None)
+ if not page_token:
+ break
+
+ if not submissions:
+ print("No student submissions found.")
+ else:
+ print("Complete list of student Submissions:")
+ for submission in submissions:
+ print(
+ f"{submission.get('id')} was submitted at"
+ f" {submission.get('creationTime')}"
+ )
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ submissions = None
+ return submissions
+
+
+if __name__ == "__main__":
+ # Put the course_id and user_id of course whose list needs to be
+ # submitted.
+ classroom_all_submissions(453686957652, 466086979658)
+# [END classroom_all_submissions]
diff --git a/classroom/snippets/classroom_create_course.py b/classroom/snippets/classroom_create_course.py
new file mode 100644
index 00000000..c471d1d8
--- /dev/null
+++ b/classroom/snippets/classroom_create_course.py
@@ -0,0 +1,61 @@
+"""
+Copyright 2018 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.
+"""
+
+# [START classroom_create_course]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_create_course():
+ """
+ Creates the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ course = {
+ "name": "10th Grade Mathematics Probability-2",
+ "section": "Period 3",
+ "descriptionHeading": "Welcome to 10th Grade Mathematics",
+ "description": """We'll be learning about about the
+ polynomials from a
+ combination of textbooks and guest lectures.
+ Expect to be excited!""",
+ "room": "302",
+ "ownerId": "me",
+ "courseState": "PROVISIONED",
+ }
+ # pylint: disable=maybe-no-member
+ course = service.courses().create(body=course).execute()
+ print(f"Course created: {(course.get('name'), course.get('id'))}")
+ return course
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ classroom_create_course()
+
+# [END classroom_create_course]
diff --git a/classroom/snippets/classroom_create_coursework.py b/classroom/snippets/classroom_create_coursework.py
new file mode 100644
index 00000000..7a41392a
--- /dev/null
+++ b/classroom/snippets/classroom_create_coursework.py
@@ -0,0 +1,65 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START classroom_create_coursework]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_create_coursework(course_id):
+ """
+ Creates the coursework the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ coursework = {
+ "title": "Ant colonies",
+ "description": """Read the article about ant colonies
+ and complete the quiz.""",
+ "materials": [
+ {"link": {"url": "http://example.com/ant-colonies"}},
+ {"link": {"url": "http://example.com/ant-quiz"}},
+ ],
+ "workType": "ASSIGNMENT",
+ "state": "PUBLISHED",
+ }
+ coursework = (
+ service.courses()
+ .courseWork()
+ .create(courseId=course_id, body=coursework)
+ .execute()
+ )
+ print(f"Assignment created with ID {coursework.get('id')}")
+ return coursework
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the course_id of course whose coursework needs to be created,
+ # the user has access to.
+ classroom_create_coursework(453686957652)
+# [END classroom_create_coursework]
diff --git a/classroom/snippets/classroom_get_course.py b/classroom/snippets/classroom_get_course.py
new file mode 100644
index 00000000..f91f31c5
--- /dev/null
+++ b/classroom/snippets/classroom_get_course.py
@@ -0,0 +1,49 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START classroom_get_course]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_get_course(course_id):
+ """
+ Prints the name of the with specific course_id.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ course = None
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ course = service.courses().get(id=course_id).execute()
+ print(f"Course found : {course.get('name')}")
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print(f"Course not found: {course_id}")
+ return error
+ return course
+
+
+if __name__ == "__main__":
+ # Put the course_id of course whose information needs to be fetched.
+ classroom_get_course("course_id")
+
+# [END classroom_get_courses]
diff --git a/classroom/snippets/classroom_invite_guardian.py b/classroom/snippets/classroom_invite_guardian.py
new file mode 100644
index 00000000..8b260c39
--- /dev/null
+++ b/classroom/snippets/classroom_invite_guardian.py
@@ -0,0 +1,59 @@
+"""
+Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+# [START classroom_invite_guardian]
+def classroom_invite_guardian():
+ """
+ Creates the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ guardian_invitation = {
+ "invitedEmailAddress": "guardian@gmail.com",
+ }
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ while True:
+ guardian_invitations = service.userProfiles().guardianInvitations()
+ guardian_invitation = guardian_invitations.create(
+ # You can use a user ID or an email address.
+ studentId="student@mydomain.edu",
+ body=guardian_invitation,
+ ).execute()
+ print(
+ "Invitation created with id: {%s}"
+ % guardian_invitation.get("invitationId")
+ )
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ # Put the course_id, coursework_id and user_id of course whose list needs
+ # to be submitted.
+ classroom_invite_guardian()
+# [END classroom_invite_guardian]
diff --git a/classroom/snippets/classroom_list_course_aliases.py b/classroom/snippets/classroom_list_course_aliases.py
new file mode 100644
index 00000000..562e13c6
--- /dev/null
+++ b/classroom/snippets/classroom_list_course_aliases.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START classroom_list_course_aliases]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_list_course_aliases(course_id):
+ """
+ Prints the list of the aliases of a specified course the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ course_aliases = []
+ page_token = None
+
+ while True:
+ response = (
+ service.courses()
+ .aliases()
+ .list(pageToken=page_token, courseId=course_id)
+ .execute()
+ )
+ course_aliases.extend(response.get("aliases", []))
+ page_token = response.get("nextPageToken", None)
+ if not page_token:
+ break
+
+ if not course_aliases:
+ print("No course aliases found.")
+
+ print("Course aliases:")
+ for course_alias in course_aliases:
+ print(f"{course_alias.get('alias')}")
+ return course_aliases
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ classroom_list_course_aliases("course_id")
+
+# [END classroom_list_course_aliases]
diff --git a/classroom/snippets/classroom_list_courses.py b/classroom/snippets/classroom_list_courses.py
new file mode 100644
index 00000000..6e8c97cd
--- /dev/null
+++ b/classroom/snippets/classroom_list_courses.py
@@ -0,0 +1,63 @@
+"""
+Copyright 2018 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.
+"""
+
+# [START classroom_list_courses]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_list_courses():
+ """
+ Prints the list of the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ courses = []
+ page_token = None
+
+ while True:
+ # pylint: disable=maybe-no-member
+ response = (
+ service.courses().list(pageToken=page_token, pageSize=100).execute()
+ )
+ courses.extend(response.get("courses", []))
+ page_token = response.get("nextPageToken", None)
+ if not page_token:
+ break
+
+ if not courses:
+ print("No courses found.")
+ return
+ print("Courses:")
+ for course in courses:
+ print(f"{course.get('name'), course.get('id')}")
+ return courses
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ print("Courses available are-------")
+ classroom_list_courses()
+
+# [END classroom_list_courses]
diff --git a/classroom/snippets/classroom_list_student_submissions.py b/classroom/snippets/classroom_list_student_submissions.py
new file mode 100644
index 00000000..c56ea8de
--- /dev/null
+++ b/classroom/snippets/classroom_list_student_submissions.py
@@ -0,0 +1,74 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START classroom_list_student_submissions]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_list_student_submissions(course_id, coursework_id, user_id):
+ """
+ Creates the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ submissions = []
+ page_token = None
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ while True:
+ coursework = service.courses().courseWork()
+ response = (
+ coursework.studentSubmissions()
+ .list(
+ pageToken=page_token,
+ courseId=course_id,
+ courseWorkId=coursework_id,
+ userId=user_id,
+ )
+ .execute()
+ )
+ submissions.extend(response.get("studentSubmissions", []))
+ page_token = response.get("nextPageToken", None)
+ if not page_token:
+ break
+
+ if not submissions:
+ print("No student submissions found.")
+
+ print("Student Submissions:")
+ for submission in submissions:
+ print(
+ "Submitted at:"
+ f"{(submission.get('id'), submission.get('creationTime'))}"
+ )
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return submissions
+
+
+if __name__ == "__main__":
+ # Put the course_id, coursework_id and user_id of course whose list needs
+ # to be submitted.
+ classroom_list_student_submissions(453686957652, 466086979658, "me")
+# [END classroom_list_student_submissions]
diff --git a/classroom/snippets/classroom_list_submissions.py b/classroom/snippets/classroom_list_submissions.py
new file mode 100644
index 00000000..e7040954
--- /dev/null
+++ b/classroom/snippets/classroom_list_submissions.py
@@ -0,0 +1,75 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START classroom_list_submissions]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_list_submissions(course_id, coursework_id):
+ """
+ Creates the courses the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ submissions = []
+ page_token = None
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ while True:
+ coursework = service.courses().courseWork()
+ response = (
+ coursework.studentSubmissions()
+ .list(
+ pageToken=page_token,
+ courseId=course_id,
+ courseWorkId=coursework_id,
+ pageSize=10,
+ )
+ .execute()
+ )
+ submissions.extend(response.get("studentSubmissions", []))
+ page_token = response.get("nextPageToken", None)
+ if not page_token:
+ break
+
+ if not submissions:
+ print("No student submissions found.")
+
+ print("Student Submissions:")
+ for submission in submissions:
+ print(
+ "Submitted at:"
+ f"{(submission.get('id'), submission.get('creationTime'))}"
+ )
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ submissions = None
+ return submissions
+
+
+if __name__ == "__main__":
+ # Put the course_id and coursework_id of course whose list needs to be
+ # submitted.
+ classroom_list_submissions(453686957652, 466086979658)
+# [END classroom_list_submissions]
diff --git a/classroom/snippets/classroom_patch_course.py b/classroom/snippets/classroom_patch_course.py
new file mode 100644
index 00000000..e1e02420
--- /dev/null
+++ b/classroom/snippets/classroom_patch_course.py
@@ -0,0 +1,52 @@
+"""Copyright 2018 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.
+"""
+
+# [START classroom_patch_course]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_patch_course(course_id):
+ """
+ Patch new course with existing course in the account the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ # pylint: disable=maybe-no-member
+
+ creds, _ = google.auth.default()
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+ course = {"section": "Period 3", "room": "313"}
+ course = (
+ service.courses()
+ .patch(id=course_id, updateMask="section,room", body=course)
+ .execute()
+ )
+ print(f" Course updated are: {course.get('name')}")
+ return course
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ # Put the course_id of course with whom we need to patch some extra
+ # information.
+ classroom_patch_course("course_id")
+
+# [END classroom_patch_course]
diff --git a/classroom/snippets/classroom_snippets.py b/classroom/snippets/classroom_snippets.py
deleted file mode 100644
index c5a00498..00000000
--- a/classroom/snippets/classroom_snippets.py
+++ /dev/null
@@ -1,326 +0,0 @@
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-from googleapiclient import errors
-
-
-class ClassroomSnippets(object):
- def __init__(self, service):
- self.service = service
-
- def create_course(self):
- """ Creates a single Classroom course. """
- service = self.service
- # [START classroom_create_course]
- course = {
- 'name': '10th Grade Biology',
- 'section': 'Period 2',
- 'descriptionHeading': 'Welcome to 10th Grade Biology',
- 'description': """We'll be learning about about the
- structure of living creatures from a
- combination of textbooks, guest lectures,
- and lab work. Expect to be excited!""",
- 'room': '301',
- 'ownerId': 'me',
- 'courseState': 'PROVISIONED'
- }
- course = service.courses().create(body=course).execute()
- print('Course created: %s %s' % (course.get('name'), course.get('id')))
- # [END classroom_create_course]
- return course
-
- def get_course(self, course_id):
- """ Retrieves a classroom course by its id. """
- service = self.service
- # [START classroom_get_course]
- try:
- course = service.courses().get(id=course_id).execute()
- print('Course "{%s}" found.' % course.get('name'))
- except errors.HttpError as error:
- print('Course with ID "{%s}" not found.' % course_id)
- # [END classroom_get_course]
- return error
- return course
-
- def list_courses(self):
- """ Lists all classroom courses. """
- service = self.service
- # [START classroom_list_courses]
- courses = []
- page_token = None
-
- while True:
- response = service.courses().list(pageToken=page_token,
- pageSize=100).execute()
- courses.extend(response.get('courses', []))
- page_token = response.get('nextPageToken', None)
- if not page_token:
- break
-
- if not courses:
- print('No courses found.')
- else:
- print('Courses:')
- for course in courses:
- print(course.get('name'), course.get('id'))
- # [END classroom_list_courses]
-
- def update_course(self, course_id):
- """ Updates the section and room of Google Classroom. """
- service = self.service
- # [START classroom_update_course]
- course = service.courses().get(id=course_id).execute()
- course['section'] = 'Period 3'
- course['room'] = '302'
- course = service.courses().update(id=course_id, body=course).execute()
- print('Course %s updated.' % course.get('name'))
- # [END classroom_update_course]
-
- def patch_course(self, course_id):
- """ Creates a course with alias specification. """
- service = self.service
- # [START classroom_patch_course]
- course = {
- 'section': 'Period 3',
- 'room': '302'
- }
- course = service.courses().patch(id=course_id,
- updateMask='section,room',
- body=course).execute()
- print('Course "%s" updated.' % course.get('name'))
- # [END classroom_patch_course]
-
- def add_alias_new(self):
- """ Creates a course with alias specification. """
- service = self.service
- # [START classroom_new_alias]
- alias = 'd:school_math_101'
- course = {
- 'id': alias,
- 'name': 'Math 101',
- 'section': 'Period 2',
- 'description': 'Course Description',
- 'room': '301',
- 'ownerId': 'me'
- }
- try:
- course = service.courses().create(
- body=course).execute()
- except errors.HttpError:
- print('Course Creation Failed')
- # [END classroom_new_alias]
-
- def add_alias_existing(self, course_id):
- """ Adds alias to existing course. """
- service = self.service
- # [START classroom_existing_alias]
- alias = 'd:school_math_101'
- course_alias = {
- 'alias': alias
- }
- try:
- course_alias = service.courses().aliases().create(
- courseId=course_id,
- body=course_alias).execute()
- except errors.HttpError:
- print('Alias Creation Failed')
- # [END classroom_existing_alias]
-
- def add_teacher(self, course_id):
- """ Adds a teacher to a course. """
- service = self.service
- # [START classroom_add_teacher]
- teacher_email = 'alice@example.edu'
- teacher = {
- 'userId': teacher_email
- }
- try:
- teachers = service.courses().teachers()
- teacher = teachers.create(courseId=course_id,
- body=teacher).execute()
- print('User %s was added as a teacher to the course with ID %s'
- % (teacher.get('profile').get('name').get('fullName'),
- course_id))
- except errors.HttpError as error:
- print('User "{%s}" is already a member of this course.'
- % teacher_email)
- # [END classroom_add_teacher]
- return error
- return teachers
-
- def add_student(self, course_id):
- """ Adds a student to a course. """
- service = self.service
- # [START classroom_add_student]
- enrollment_code = 'abcdef'
- student = {
- 'userId': 'me'
- }
- try:
- student = service.courses().students().create(
- courseId=course_id,
- enrollmentCode=enrollment_code,
- body=student).execute()
- print(
- '''User {%s} was enrolled as a student in
- the course with ID "{%s}"'''
- % (student.get('profile').get('name').get('fullName'),
- course_id))
- except errors.HttpError as error:
- print('You are already a member of this course.')
- # [END classroom_add_student]
- return error
- return student
-
- def create_coursework(self, course_id):
- """ Creates a coursework. """
- service = self.service
- # [START classroom_create_coursework]
- coursework = {
- 'title': 'Ant colonies',
- 'description': '''Read the article about ant colonies
- and complete the quiz.''',
- 'materials': [
- {'link': {'url': 'http://example.com/ant-colonies'}},
- {'link': {'url': 'http://example.com/ant-quiz'}}
- ],
- 'workType': 'ASSIGNMENT',
- 'state': 'PUBLISHED',
- }
- coursework = service.courses().courseWork().create(
- courseId=course_id, body=coursework).execute()
- print('Assignment created with ID {%s}' % coursework.get('id'))
- # [END classroom_create_coursework]
-
- def list_submissions(self, course_id, coursework_id):
- """ Lists all student submissions for a given coursework. """
- service = self.service
- # [START classroom_list_submissions]
- submissions = []
- page_token = None
-
- while True:
- coursework = service.courses().courseWork()
- response = coursework.studentSubmissions().list(
- pageToken=page_token,
- courseId=course_id,
- courseWorkId=coursework_id,
- pageSize=10).execute()
- submissions.extend(response.get('studentSubmissions', []))
- page_token = response.get('nextPageToken', None)
- if not page_token:
- break
-
- if not submissions:
- print('No student submissions found.')
- else:
- print('Student Submissions:')
- for submission in submissions:
- print("%s was submitted at %s" %
- (submission.get('id'),
- submission.get('creationTime')))
- # [END classroom_list_submissions]
-
- def list_student_submissions(self, course_id, coursework_id, user_id):
- """ Lists all coursework submissions for a given student. """
- service = self.service
- # [START classroom_list_student_submissions]
- submissions = []
- page_token = None
-
- while True:
- coursework = service.courses().courseWork()
- response = coursework.studentSubmissions().list(
- pageToken=page_token,
- courseId=course_id,
- courseWorkId=coursework_id,
- userId=user_id).execute()
- submissions.extend(response.get('studentSubmissions', []))
- page_token = response.get('nextPageToken', None)
- if not page_token:
- break
-
- if not submissions:
- print('No student submissions found.')
- else:
- print('Student Submissions:')
- for submission in submissions:
- print("%s was submitted at %s" %
- (submission.get('id'),
- submission.get('creationTime')))
- # [END classroom_list_student_submissions]
-
- def list_all_submissions(self, course_id, user_id):
- """ Lists all coursework submissions for a given student. """
- service = self.service
- # [START classroom_list_submissions]
- submissions = []
- page_token = None
-
- while True:
- coursework = service.courses().courseWork()
- response = coursework.studentSubmissions().list(
- pageToken=page_token,
- courseId=course_id,
- courseWorkId="-",
- userId=user_id).execute()
- submissions.extend(response.get('studentSubmissions', []))
- page_token = response.get('nextPageToken', None)
- if not page_token:
- break
-
- if not submissions:
- print('No student submissions found.')
- else:
- print('Complete list of student Submissions:')
- for submission in submissions:
- print("%s was submitted at %s" %
- (submission.get('id'),
- submission.get('creationTime')))
- # [END classroom_list_submissions]
-
- def add_attachment(self, course_id, coursework_id, submission_id):
- """ Adds an attachment to a student submission. """
- service = self.service
- # [START classroom_add_attachment]
- request = {
- 'addAttachments': [
- {'link': {'url': 'http://example.com/quiz-results'}},
- {'link': {'url': 'http://example.com/quiz-reading'}}
- ]
- }
- coursework = service.courses().courseWork()
- coursework.studentSubmissions().modifyAttachments(
- courseId=course_id,
- courseWorkId=coursework_id,
- id=submission_id,
- body=request).execute()
- # [END classroom_add_attachment]
-
- def invite_guardian(self):
- """ Send an invite to a guardian. """
- service = self.service
- # [START classroom_add_attachment]
- guardian_invitation = {
- 'invitedEmailAddress': 'guardian@gmail.com',
- }
- guardian_invitations = service.userProfiles().guardianInvitations()
- guardian_invitation = guardian_invitations.create(
- # You can use a user ID or an email address.
- studentId='student@mydomain.edu',
- body=guardian_invitation).execute()
- print("Invitation created with id: {%s}"
- % guardian_invitation.get('invitationId'))
diff --git a/classroom/snippets/classroom_update_course.py b/classroom/snippets/classroom_update_course.py
new file mode 100644
index 00000000..25ac1f3e
--- /dev/null
+++ b/classroom/snippets/classroom_update_course.py
@@ -0,0 +1,55 @@
+"""
+Copyright 2018 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.
+"""
+
+# [START classroom_update_course]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def classroom_update_course(course_id):
+ """
+ Updates the courses names the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ # pylint: disable=maybe-no-member
+
+ creds, _ = google.auth.default()
+
+ try:
+ service = build("classroom", "v1", credentials=creds)
+
+ # Updates the section and room of Google Classroom.
+ course = service.courses().get(id=course_id).execute()
+ course["name"] = "10th Grade Physics - Light"
+ course["section"] = "Period 4"
+ course["room"] = "410"
+ course = service.courses().update(id=course_id, body=course).execute()
+ print(f" Updated Course is: {course.get('name')}")
+ return course
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the course_id of course whose course needs to be updated.
+ classroom_update_course("course_id")
+
+# [END classroom_update_course]
diff --git a/classroom/snippets/test_classroom_create_course.py b/classroom/snippets/test_classroom_create_course.py
new file mode 100644
index 00000000..8d5c76da
--- /dev/null
+++ b/classroom/snippets/test_classroom_create_course.py
@@ -0,0 +1,31 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import classroom_create_course
+from base_test import BaseTest
+
+
+class TestClassroomCreateCourse(BaseTest):
+ """Unit test class for Create course snippet"""
+
+ def test_classroom_create_course(self):
+ """Class function for Create course snippet"""
+ course = classroom_create_course.classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_classroom_get_course.py b/classroom/snippets/test_classroom_get_course.py
new file mode 100644
index 00000000..0ca05299
--- /dev/null
+++ b/classroom/snippets/test_classroom_get_course.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import classroom_create_course
+import classroom_get_course
+from base_test import BaseTest
+
+
+class TestClassroomGetCourse(BaseTest):
+ """Unit test class for Get course snippet"""
+
+ def test_classroom_get_course(self):
+ """Unit test method for Get course snippet"""
+ course = classroom_create_course.classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+ course_id = classroom_get_course.classroom_get_course(course.get("id"))
+ self.assertIsNotNone(course_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_classroom_list_course_aliases.py b/classroom/snippets/test_classroom_list_course_aliases.py
new file mode 100644
index 00000000..f68b81ea
--- /dev/null
+++ b/classroom/snippets/test_classroom_list_course_aliases.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from base_test import BaseTest
+from classroom_create_course import classroom_create_course
+from classroom_list_course_aliases import classroom_list_course_aliases
+
+
+class TestClassroomListCourseAliases(BaseTest):
+ """Unit test class for List course aliases snippet"""
+
+ def test_classroom_list_course_aliases(self):
+ """Unit test method for List course snippet"""
+ course = classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+ course_aliases = classroom_list_course_aliases(course.get("id"))
+ self.assertIsNotNone(course_aliases)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_classroom_list_courses.py b/classroom/snippets/test_classroom_list_courses.py
new file mode 100644
index 00000000..81fc27f1
--- /dev/null
+++ b/classroom/snippets/test_classroom_list_courses.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import classroom_create_course
+import classroom_list_courses
+from base_test import BaseTest
+
+
+class TestClassroomListCourses(BaseTest):
+ """Unit test class for List course snippet"""
+
+ def test_classroom_list_courses(self):
+ """Unit test method for List course snippet"""
+ course = classroom_create_course.classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+ courses = classroom_list_courses.classroom_list_courses()
+ self.assertIsNotNone(courses)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_classroom_patch_course.py b/classroom/snippets/test_classroom_patch_course.py
new file mode 100644
index 00000000..43a4862f
--- /dev/null
+++ b/classroom/snippets/test_classroom_patch_course.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import classroom_create_course
+import classroom_patch_course
+from base_test import BaseTest
+
+
+class TestClassroomPatchCourse(BaseTest):
+ """Unit test class for Patch course snippet"""
+
+ def test_classroom_patch_course(self):
+ """Unit test method for Patch course snippet"""
+ course = classroom_create_course.classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+ course = classroom_patch_course.classroom_patch_course(course.get("id"))
+ self.assertIsNotNone(course)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_classroom_update_course.py b/classroom/snippets/test_classroom_update_course.py
new file mode 100644
index 00000000..ccfcdd4b
--- /dev/null
+++ b/classroom/snippets/test_classroom_update_course.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import classroom_create_course
+import classroom_update_course
+from base_test import BaseTest
+
+
+class TestClassroomUpdateCourse(BaseTest):
+ """Unit test class for Get course snippet"""
+
+ def test_classroom_update_course(self):
+ """Unit test method for Get course snippet"""
+ course = classroom_create_course.classroom_create_course()
+ self.assertIsNotNone(course)
+ self.delete_course_on_cleanup(course.get("id"))
+ course = classroom_update_course.classroom_update_course(course.get("id"))
+ self.assertIsNotNone(course)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/classroom/snippets/test_snippets.py b/classroom/snippets/test_snippets.py
deleted file mode 100644
index ffb3c3d6..00000000
--- a/classroom/snippets/test_snippets.py
+++ /dev/null
@@ -1,36 +0,0 @@
-
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from base_test import BaseTest
-from classroom_snippets import ClassroomSnippets
-
-
-class SnippetsTest(BaseTest):
-
- @classmethod
- def setUpClass(cls):
- super(SnippetsTest, cls).setUpClass()
- cls.snippets = ClassroomSnippets(cls.service)
-
- def test_create_course(self):
- course = self.snippets.create_course()
- self.assertIsNotNone(course)
- self.delete_course_on_cleanup(course.get('id'))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/docs/mail-merge/docs_mail_merge.py b/docs/mail-merge/docs_mail_merge.py
index 2af4d89e..45d68840 100644
--- a/docs/mail-merge/docs_mail_merge.py
+++ b/docs/mail-merge/docs_mail_merge.py
@@ -11,6 +11,7 @@
# 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.
+# pylint: disable=(consider-using-f-string)
"""
docs-mail-merge.py (Python 2.x or 3.x)
@@ -18,145 +19,170 @@
Google Docs (REST) API mail-merge sample app
"""
# [START mail_merge_python]
-from __future__ import print_function
-
import time
-from googleapiclient import discovery
-from httplib2 import Http
-from oauth2client import client, file, tools
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
# Fill-in IDs of your Docs template & any Sheets data source
-DOCS_FILE_ID = 'YOUR_TMPL_DOC_FILE_ID'
-SHEETS_FILE_ID = 'YOUR_SHEET_DATA_FILE_ID'
+DOCS_FILE_ID = "195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE"
+SHEETS_FILE_ID = "11pPEzi1vCMNbdpqaQx4N43rKmxvZlgEHE9GqpYoEsWw"
# authorization constants
-CLIENT_ID_FILE = 'credentials.json'
-TOKEN_STORE_FILE = 'token.json'
+
SCOPES = ( # iterable or space-delimited string
- 'https://www.googleapis.com/auth/drive',
- 'https://www.googleapis.com/auth/documents',
- 'https://www.googleapis.com/auth/spreadsheets.readonly',
+ "https://www.googleapis.com/auth/drive",
+ "https://www.googleapis.com/auth/documents",
+ "https://www.googleapis.com/auth/spreadsheets.readonly",
)
# application constants
-SOURCES = ('text', 'sheets')
-SOURCE = 'text' # Choose one of the data SOURCES
-COLUMNS = ['to_name', 'to_title', 'to_company', 'to_address']
+SOURCES = ("text", "sheets")
+SOURCE = "text" # Choose one of the data SOURCES
+COLUMNS = ["to_name", "to_title", "to_company", "to_address"]
TEXT_SOURCE_DATA = (
- ('Ms. Lara Brown', 'Googler', 'Google NYC', '111 8th Ave\n'
- 'New York, NY 10011-5201'),
- ('Mr. Jeff Erson', 'Googler', 'Google NYC', '76 9th Ave\n'
- 'New York, NY 10011-4962'),
+ (
+ "Ms. Lara Brown",
+ "Googler",
+ "Google NYC",
+ "111 8th Ave\nNew York, NY 10011-5201",
+ ),
+ (
+ "Mr. Jeff Erson",
+ "Googler",
+ "Google NYC",
+ "76 9th Ave\nNew York, NY 10011-4962",
+ ),
)
-
-def get_http_client():
- """Uses project credentials in CLIENT_ID_FILE along with requested OAuth2
- scopes for authorization, and caches API tokens in TOKEN_STORE_FILE.
- """
- store = file.Storage(TOKEN_STORE_FILE)
- creds = store.get()
- if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets(CLIENT_ID_FILE, SCOPES)
- creds = tools.run_flow(flow, store)
- return creds.authorize(Http())
-
+# fill-in your data to merge into document template variables
+merge = {
+ # sender data
+ "my_name": "Ayme A. Coder",
+ "my_address": "1600 Amphitheatre Pkwy\nMountain View, CA 94043-1351",
+ "my_email": "http://google.com/",
+ "my_phone": "+1-650-253-0000",
+ # - - - - - - - - - - - - - - - - - - - - - - - - - -
+ # recipient data (supplied by 'text' or 'sheets' data source)
+ "to_name": None,
+ "to_title": None,
+ "to_company": None,
+ "to_address": None,
+ # - - - - - - - - - - - - - - - - - - - - - - - - - -
+ "date": time.strftime("%Y %B %d"),
+ # - - - - - - - - - - - - - - - - - - - - - - - - - -
+ "body": (
+ "Google, headquartered in Mountain View, unveiled the new "
+ "Android phone at the Consumer Electronics Show. CEO Sundar "
+ "Pichai said in his keynote that users love their new phones."
+ ),
+}
+
+creds, _ = google.auth.default()
+# pylint: disable=maybe-no-member
# service endpoints to Google APIs
-HTTP = get_http_client()
-DRIVE = discovery.build('drive', 'v3', http=HTTP)
-DOCS = discovery.build('docs', 'v1', http=HTTP)
-SHEETS = discovery.build('sheets', 'v4', http=HTTP)
+
+DRIVE = build("drive", "v2", credentials=creds)
+DOCS = build("docs", "v1", credentials=creds)
+SHEETS = build("sheets", "v4", credentials=creds)
def get_data(source):
- """Gets mail merge data from chosen data source.
- """
- if source not in {'sheets', 'text'}:
- raise ValueError('ERROR: unsupported source %r; choose from %r' % (
- source, SOURCES))
+ """Gets mail merge data from chosen data source."""
+ try:
+ if source not in {"sheets", "text"}:
+ raise ValueError(
+ f"ERROR: unsupported source {source}; choose from {SOURCES}"
+ )
return SAFE_DISPATCH[source]()
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
def _get_text_data():
- """(private) Returns plain text data; can alter to read from CSV file.
- """
- return TEXT_SOURCE_DATA
+ """(private) Returns plain text data; can alter to read from CSV file."""
+ return TEXT_SOURCE_DATA
def _get_sheets_data(service=SHEETS):
- """(private) Returns data from Google Sheets source. It gets all rows of
- 'Sheet1' (the default Sheet in a new spreadsheet), but drops the first
- (header) row. Use any desired data range (in standard A1 notation).
- """
- return service.spreadsheets().values().get(spreadsheetId=SHEETS_FILE_ID,
- range='Sheet1').execute().get('values')[1:] # skip header row
+ """(private) Returns data from Google Sheets source. It gets all rows of
+ 'Sheet1' (the default Sheet in a new spreadsheet), but drops the first
+ (header) row. Use any desired data range (in standard A1 notation).
+ """
+ return (
+ service.spreadsheets()
+ .values()
+ .get(spreadsheetId=SHEETS_FILE_ID, range="Sheet1")
+ .execute()
+ .get("values")[1:]
+ )
+ # skip header row
# data source dispatch table [better alternative vs. eval()]
-SAFE_DISPATCH = {k: globals().get('_get_%s_data' % k) for k in SOURCES}
+SAFE_DISPATCH = {k: globals().get(f"_get_{k}_data") for k in SOURCES}
def _copy_template(tmpl_id, source, service):
- """(private) Copies letter template document using Drive API then
- returns file ID of (new) copy.
- """
- body = {'name': 'Merged form letter (%s)' % source}
- return service.files().copy(body=body, fileId=tmpl_id,
- fields='id').execute().get('id')
+ """(private) Copies letter template document using Drive API then
+ returns file ID of (new) copy.
+ """
+ try:
+ body = {"name": f"Merged form letter ({source})"}
+ return (
+ service.files()
+ .copy(body=body, fileId=tmpl_id, fields="id")
+ .execute()
+ .get("id")
+ )
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
def merge_template(tmpl_id, source, service):
- """Copies template document and merges data into newly-minted copy then
- returns its file ID.
- """
+ """Copies template document and merges data into newly-minted copy then
+ returns its file ID.
+ """
+ try:
# copy template and set context data struct for merging template values
copy_id = _copy_template(tmpl_id, source, service)
- context = merge.iteritems() if hasattr({}, 'iteritems') else merge.items()
+ context = merge.iteritems() if hasattr({}, "iteritems") else merge.items()
# "search & replace" API requests for mail merge substitutions
- reqs = [{'replaceAllText': {
- 'containsText': {
- 'text': '{{%s}}' % key.upper(), # {{VARS}} are uppercase
- 'matchCase': True,
- },
- 'replaceText': value,
- }} for key, value in context]
+ reqs = [
+ {
+ "replaceAllText": {
+ "containsText": {
+ "text": "{{%s}}" % key.upper(), # {{VARS}} are uppercase
+ "matchCase": True,
+ },
+ "replaceText": value,
+ }
+ }
+ for key, value in context
+ ]
# send requests to Docs API to do actual merge
- DOCS.documents().batchUpdate(body={'requests': reqs},
- documentId=copy_id, fields='').execute()
+ DOCS.documents().batchUpdate(
+ body={"requests": reqs}, documentId=copy_id, fields=""
+ ).execute()
return copy_id
-
-
-if __name__ == '__main__':
- # fill-in your data to merge into document template variables
- merge = {
- # sender data
- 'my_name': 'Ayme A. Coder',
- 'my_address': '1600 Amphitheatre Pkwy\n'
- 'Mountain View, CA 94043-1351',
- 'my_email': 'http://google.com/',
- 'my_phone': '+1-650-253-0000',
- # - - - - - - - - - - - - - - - - - - - - - - - - - -
- # recipient data (supplied by 'text' or 'sheets' data source)
- 'to_name': None,
- 'to_title': None,
- 'to_company': None,
- 'to_address': None,
- # - - - - - - - - - - - - - - - - - - - - - - - - - -
- 'date': time.strftime('%Y %B %d'),
- # - - - - - - - - - - - - - - - - - - - - - - - - - -
- 'body': 'Google, headquartered in Mountain View, unveiled the new '
- 'Android phone at the Consumer Electronics Show. CEO Sundar '
- 'Pichai said in his keynote that users love their new phones.'
- }
-
- # get row data, then loop through & process each form letter
- data = get_data(SOURCE) # get data from data source
- for i, row in enumerate(data):
- merge.update(dict(zip(COLUMNS, row)))
- print('Merged letter %d: docs.google.com/document/d/%s/edit' % (
- i + 1, merge_template(DOCS_FILE_ID, SOURCE, DRIVE)))
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # get row data, then loop through & process each form letter
+ data = get_data(SOURCE) # get data from data source
+ for i, row in enumerate(data):
+ merge.update(dict(zip(COLUMNS, row)))
+ print(
+ "Merged letter %d: docs.google.com/document/d/%s/edit"
+ % (i + 1, merge_template(DOCS_FILE_ID, SOURCE, DRIVE))
+ )
# [END mail_merge_python]
diff --git a/docs/mail-merge/docs_mail_merge_test.py b/docs/mail-merge/docs_mail_merge_test.py
index 7020b58f..276d8f14 100644
--- a/docs/mail-merge/docs_mail_merge_test.py
+++ b/docs/mail-merge/docs_mail_merge_test.py
@@ -25,76 +25,66 @@
import unittest
import google.auth
-from docs_mail_merge import _copy_template, get_data, get_http_client
+from docs_mail_merge import _copy_template, get_data
from googleapiclient import discovery
+creds, _ = google.auth.default()
-class TestDocsMailMerge(unittest.TestCase):
- 'Unit tests for Mail Merge sample'
- def test_project(self):
- self.assertTrue(project_test())
+class TestDocsMailMerge(unittest.TestCase):
+ "Unit tests for Mail Merge sample"
- def test_gapis(self):
- self.assertTrue(gapis_test())
+ def test_project(self):
+ self.assertTrue(project_test())
- def test_create_doc(self):
- self.assertTrue(create_doc_test())
+ def test_create_doc(self):
+ self.assertTrue(create_doc_test())
- def test_copy_doc(self):
- self.assertTrue(copy_doc_test())
+ def test_copy_doc(self):
+ self.assertTrue(copy_doc_test())
- def test_get_text_data(self):
- self.assertTrue(bool(get_text_data_test()))
+ def test_get_text_data(self):
+ self.assertTrue(bool(get_text_data_test()))
- def test_get_sheets_data(self):
- self.assertTrue(bool(get_sheets_data_test()))
+ def test_get_sheets_data(self):
+ self.assertTrue(bool(get_sheets_data_test()))
def project_test():
- 'Tests whether project credentials file was downloaded from project.'
- credentials, project = google.auth.default()
-
-
-def gapis_test():
- 'Tests whether project can connect to all 3 APIs used in the sample.'
- HTTP = get_http_client()
- discovery.build('drive', 'v3', http=HTTP)
- discovery.build('docs', 'v1', http=HTTP)
- discovery.build('sheets', 'v4', http=HTTP)
- return True
+ "Tests whether project credentials file was downloaded from project."
+ credentials, project = google.auth.default()
def create_doc_test():
- 'Tests whether project can create and delete a Google Docs file.'
- DRIVE = discovery.build('drive', 'v3', http=get_http_client())
- DATA = {
- 'name': 'Test Doc',
- 'mimeType': 'application/vnd.google-apps.document',
- }
- doc_id = DRIVE.files().create(body=DATA, fields='id').execute().get('id')
- DRIVE.files().delete(fileId=doc_id, fields='').execute()
- return True
+ "Tests whether project can create and delete a Google Docs file."
+ DRIVE = discovery.build("drive", "v3", credentials=creds)
+ DATA = {
+ "name": "Test Doc",
+ "mimeType": "application/vnd.google-apps.document",
+ }
+ doc_id = DRIVE.files().create(body=DATA, fields="id").execute().get("id")
+ DRIVE.files().delete(fileId=doc_id, fields="").execute()
+ return True
def copy_doc_test():
- 'Tests whether project can copy and delete a Google Docs file.'
- DRIVE = discovery.build('drive', 'v3', http=get_http_client())
- DOCS_FILE_ID = '1Xycxuuv7OhEQUuzbt_Mw0TPMq02MseSD1vZdBJ3nLjk'
- doc_id = _copy_template(DOCS_FILE_ID, 'text', DRIVE)
- DRIVE.files().delete(fileId=doc_id, fields='').execute()
- return True
+ "Tests whether project can copy and delete a Google Docs file."
+ DRIVE = discovery.build("drive", "v3", credentials=creds)
+ DOCS_FILE_ID = "1Xycxuuv7OhEQUuzbt_Mw0TPMq02MseSD1vZdBJ3nLjk"
+ doc_id = _copy_template(DOCS_FILE_ID, "text", DRIVE)
+ DRIVE.files().delete(fileId=doc_id, fields="").execute()
+ return True
def get_text_data_test():
- 'Tests reading plain text data.'
- return get_data('text')
+ "Tests reading plain text data."
+ return get_data("text")
def get_sheets_data_test():
- 'Tests reading Google Sheets data.'
- return get_data('sheets')
+ "Tests reading Google Sheets data."
+ return get_data("sheets")
-if __name__ == '__main__':
- unittest.main()
+if __name__ == "__main__":
+ unittest.main()
diff --git a/docs/output-json/output-json.py b/docs/output-json/output-json.py
index 71b88e93..082b08d4 100644
--- a/docs/output-json/output-json.py
+++ b/docs/output-json/output-json.py
@@ -17,8 +17,6 @@
Google Docs (REST) API output-json sample app
"""
# [START output_json_python]
-from __future__ import print_function
-
import json
from apiclient import discovery
@@ -26,23 +24,26 @@
from oauth2client import client, file, tools
# Set doc ID, as found at `https://docs.google.com/document/d/YOUR_DOC_ID/edit`
-DOCUMENT_ID = 'YOUR_DOC_ID'
+DOCUMENT_ID = "YOUR_DOC_ID"
# Set the scopes and discovery info
-SCOPES = 'https://www.googleapis.com/auth/documents.readonly'
-DISCOVERY_DOC = ('https://docs.googleapis.com/$discovery/rest?'
- 'version=v1')
+SCOPES = "https://www.googleapis.com/auth/documents.readonly"
+DISCOVERY_DOC = "https://docs.googleapis.com/$discovery/rest?version=v1"
# Initialize credentials and instantiate Docs API service
-store = file.Storage('token.json')
+store = file.Storage("token.json")
creds = store.get()
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('docs', 'v1', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC)
+ flow = client.flow_from_clientsecrets("credentials.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "docs",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+)
# Do a document "get" request and print the results as formatted JSON
-result = service.documents().get(documentId=DOCUMENT_ID).execute()
+result = service.documents().get(documentId=DOCUMENT_ID, includeTabsContent=True).execute()
print(json.dumps(result, indent=4, sort_keys=True))
# [END output_json_python]
diff --git a/docs/output-json/output_json.py b/docs/output-json/output_json.py
new file mode 100644
index 00000000..caebb10e
--- /dev/null
+++ b/docs/output-json/output_json.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright ©2018-2019 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 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.
+
+"""
+ouput-json.py (Python 2.x or 3.x)
+Google Docs (REST) API output-json sample app
+"""
+# [START output_json_python]
+import json
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+# Set doc ID, as found at `https://docs.google.com/document/d/YOUR_DOC_ID/edit`
+DOCUMENT_ID = "195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE"
+
+# Set the scopes and discovery info
+SCOPES = "https://www.googleapis.com/auth/documents.readonly"
+DISCOVERY_DOC = "https://docs.googleapis.com/$discovery/rest?version=v1"
+
+# Initialize credentials and instantiate Docs API service
+creds, _ = google.auth.default()
+# pylint: disable=maybe-no-member
+try:
+ service = build("docs", "v1", credentials=creds)
+
+ # Do a document "get" request and print the results as formatted JSON
+
+ result = service.documents().get(documentId=DOCUMENT_ID).execute()
+ print(json.dumps(result, indent=4, sort_keys=True))
+except HttpError as error:
+ print(f"An error occurred: {error}")
+
+# [END output_json_python]
diff --git a/docs/quickstart/quickstart.py b/docs/quickstart/quickstart.py
index 3e4b3e45..60324159 100644
--- a/docs/quickstart/quickstart.py
+++ b/docs/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START docs_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,45 +22,46 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/documents.readonly']
+SCOPES = ["https://www.googleapis.com/auth/documents.readonly"]
# The ID of a sample document.
-DOCUMENT_ID = '195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE'
+DOCUMENT_ID = "195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE"
def main():
- """Shows basic usage of the Docs API.
- Prints the title of a sample document.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Docs API.
+ Prints the title of a sample document.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('docs', 'v1', credentials=creds)
+ try:
+ service = build("docs", "v1", credentials=creds)
- # Retrieve the documents contents from the Docs service.
- document = service.documents().get(documentId=DOCUMENT_ID).execute()
+ # Retrieve the documents contents from the Docs service.
+ document = service.documents().get(documentId=DOCUMENT_ID).execute()
- print('The title of the document is: {}'.format(document.get('title')))
- except HttpError as err:
- print(err)
+ print(f"The title of the document is: {document.get('title')}")
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END docs_quickstart]
diff --git a/drive/activity-v2/quickstart.py b/drive/activity-v2/quickstart.py
index 8e5ef54a..6e1b7769 100644
--- a/drive/activity-v2/quickstart.py
+++ b/drive/activity-v2/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START drive_activity_v2_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,114 +22,113 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/drive.activity.readonly']
+SCOPES = ["https://www.googleapis.com/auth/drive.activity.readonly"]
def main():
- """Shows basic usage of the Drive Activity API.
-
- Prints information about the last 10 events that occured the user's Drive.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
-
- service = build('driveactivity', 'v2', credentials=creds)
-
- # Call the Drive Activity API
- try:
- results = service.activity().query(body={
- 'pageSize': 10
- }).execute()
- activities = results.get('activities', [])
-
- if not activities:
- print('No activity.')
- else:
- print('Recent activity:')
- for activity in activities:
- time = getTimeInfo(activity)
- action = getActionInfo(activity['primaryActionDetail'])
- actors = map(getActorInfo, activity['actors'])
- targets = map(getTargetInfo, activity['targets'])
- actors_str, targets_str = "", ""
- actor_name = actors_str.join(actors)
- target_name = targets_str.join(targets)
-
- # Print the action occurred on drive with actor, target item and timestamp
- print(u'{0}: {1}, {2}, {3}'.format(time, action, actor_name, target_name))
-
- except HttpError as error:
- # TODO(developer) - Handleerrors from drive activity API.
- print(f'An error occurred: {error}')
+ """Shows basic usage of the Drive Activity API.
+
+ Prints information about the last 10 events that occured the user's Drive.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
+
+ service = build("driveactivity", "v2", credentials=creds)
+
+ # Call the Drive Activity API
+ try:
+ results = service.activity().query(body={"pageSize": 10}).execute()
+ activities = results.get("activities", [])
+
+ if not activities:
+ print("No activity.")
+ else:
+ print("Recent activity:")
+ for activity in activities:
+ time = getTimeInfo(activity)
+ action = getActionInfo(activity["primaryActionDetail"])
+ actors = map(getActorInfo, activity["actors"])
+ targets = map(getTargetInfo, activity["targets"])
+ actors_str, targets_str = "", ""
+ actor_name = actors_str.join(actors)
+ target_name = targets_str.join(targets)
+
+ # Print the action occurred on drive with actor, target item and timestamp
+ print(f"{time}: {action}, {actor_name}, {target_name}")
+
+ except HttpError as error:
+ # TODO(developer) - Handleerrors from drive activity API.
+ print(f"An error occurred: {error}")
# Returns the name of a set property in an object, or else "unknown".
def getOneOf(obj):
- for key in obj:
- return key
- return 'unknown'
+ for key in obj:
+ return key
+ return "unknown"
# Returns a time associated with an activity.
def getTimeInfo(activity):
- if 'timestamp' in activity:
- return activity['timestamp']
- if 'timeRange' in activity:
- return activity['timeRange']['endTime']
- return 'unknown'
+ if "timestamp" in activity:
+ return activity["timestamp"]
+ if "timeRange" in activity:
+ return activity["timeRange"]["endTime"]
+ return "unknown"
# Returns the type of action.
def getActionInfo(actionDetail):
- return getOneOf(actionDetail)
+ return getOneOf(actionDetail)
# Returns user information, or the type of user if not a known user.
def getUserInfo(user):
- if 'knownUser' in user:
- knownUser = user['knownUser']
- isMe = knownUser.get('isCurrentUser', False)
- return u'people/me' if isMe else knownUser['personName']
- return getOneOf(user)
+ if "knownUser" in user:
+ knownUser = user["knownUser"]
+ isMe = knownUser.get("isCurrentUser", False)
+ return "people/me" if isMe else knownUser["personName"]
+ return getOneOf(user)
# Returns actor information, or the type of actor if not a user.
def getActorInfo(actor):
- if 'user' in actor:
- return getUserInfo(actor['user'])
- return getOneOf(actor)
+ if "user" in actor:
+ return getUserInfo(actor["user"])
+ return getOneOf(actor)
# Returns the type of a target and an associated title.
def getTargetInfo(target):
- if 'driveItem' in target:
- title = target['driveItem'].get('title', 'unknown')
- return 'driveItem:"{0}"'.format(title)
- if 'drive' in target:
- title = target['drive'].get('title', 'unknown')
- return 'drive:"{0}"'.format(title)
- if 'fileComment' in target:
- parent = target['fileComment'].get('parent', {})
- title = parent.get('title', 'unknown')
- return 'fileComment:"{0}"'.format(title)
- return '{0}:unknown'.format(getOneOf(target))
-
-
-if __name__ == '__main__':
- main()
+ if "driveItem" in target:
+ title = target["driveItem"].get("title", "unknown")
+ return f'driveItem:"{title}"'
+ if "drive" in target:
+ title = target["drive"].get("title", "unknown")
+ return f'drive:"{title}"'
+ if "fileComment" in target:
+ parent = target["fileComment"].get("parent", {})
+ title = parent.get("title", "unknown")
+ return f'fileComment:"{title}"'
+ return f"{getOneOf(target)}:unknown"
+
+
+if __name__ == "__main__":
+ main()
# [END drive_activity_v2_quickstart]
diff --git a/drive/driveapp/main.py b/drive/driveapp/main.py
index 03da783f..fa5b1437 100644
--- a/drive/driveapp/main.py
+++ b/drive/driveapp/main.py
@@ -1,12 +1,24 @@
#!/usr/bin/python
+# Copyright 2022 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.
+
"""Google Drive Quickstart in Python.
This script uploads a single file to Google Drive.
"""
-from __future__ import print_function
-
import googleapiclient.http
import httplib2
import oauth2client.client
@@ -16,57 +28,57 @@
# OAuth 2.0 scope that will be authorized.
# Check https://developers.google.com/drive/scopes for all available scopes.
-OAUTH2_SCOPE = 'https://www.googleapis.com/auth/drive'
+OAUTH2_SCOPE = "https://www.googleapis.com/auth/drive"
# Location of the client secrets.
-CLIENT_SECRETS = 'client_secrets.json'
+CLIENT_SECRETS = "client_secrets.json"
# Path to the file to upload.
-FILENAME = 'document.txt'
+FILENAME = "document.txt"
# Metadata about the file.
-MIMETYPE = 'text/plain'
-TITLE = 'My New Text Document'
-DESCRIPTION = 'A shiny new text document about hello world.'
+MIMETYPE = "text/plain"
+TITLE = "My New Text Document"
+DESCRIPTION = "A shiny new text document about hello world."
# Perform OAuth2.0 authorization flow.
-flow = oauth2client.client.flow_from_clientsecrets(
- CLIENT_SECRETS, OAUTH2_SCOPE)
+flow = oauth2client.client.flow_from_clientsecrets(CLIENT_SECRETS, OAUTH2_SCOPE)
flow.redirect_uri = oauth2client.client.OOB_CALLBACK_URN
authorize_url = flow.step1_get_authorize_url()
-print('Go to the following link in your browser: ' + authorize_url)
+print("Go to the following link in your browser: " + authorize_url)
# `six` library supports Python2 and Python3 without redefining builtin input()
-code = six.moves.input('Enter verification code: ').strip()
+code = six.moves.input("Enter verification code: ").strip()
credentials = flow.step2_exchange(code)
# Create an authorized Drive API client.
http = httplib2.Http()
credentials.authorize(http)
-drive_service = build('drive', 'v2', http=http)
+drive_service = build("drive", "v2", http=http)
# Insert a file. Files are comprised of contents and metadata.
# MediaFileUpload abstracts uploading file contents from a file on disk.
media_body = googleapiclient.http.MediaFileUpload(
- FILENAME,
- mimetype=MIMETYPE,
- resumable=True
+ FILENAME, mimetype=MIMETYPE, resumable=True
)
# The body contains the metadata for the file.
body = {
- 'title': TITLE,
- 'description': DESCRIPTION,
+ "title": TITLE,
+ "description": DESCRIPTION,
}
# Perform the request and print the result.
try:
- new_file = drive_service.files().insert(
- body=body, media_body=media_body).execute()
- file_title = new_file.get('title')
- file_desc = new_file.get('description')
- if file_title == TITLE and file_desc == DESCRIPTION:
- print(f"File is uploaded \nTitle : {file_title} \nDescription : {file_desc}")
+ new_file = (
+ drive_service.files().insert(body=body, media_body=media_body).execute()
+ )
+ file_title = new_file.get("title")
+ file_desc = new_file.get("description")
+ if file_title == TITLE and file_desc == DESCRIPTION:
+ print(
+ f"File is uploaded \nTitle : {file_title} \nDescription : {file_desc}"
+ )
except HttpError as error:
- # TODO(developer) - Handle errors from drive API.
- print(f'An error occurred: {error}')
+ # TODO(developer) - Handle errors from drive API.
+ print(f"An error occurred: {error}")
diff --git a/drive/quickstart/README.md b/drive/quickstart/README.md
index 2aabc91a..0c283378 100644
--- a/drive/quickstart/README.md
+++ b/drive/quickstart/README.md
@@ -9,7 +9,7 @@ makes requests to the Drive V3 API.
- Python
- Create a project
- Activate the Drive API in the Google API Console([the detail page](https://developers.google.com/workspace/guides/create-project))
-- Create a OAuth client ID credential and download the json file ([the datil page](https://developers.google.com/workspace/guides/create-credentials))
+- Create a OAuth client ID credential and download the json file ([the detail page](https://developers.google.com/workspace/guides/create-credentials))
- Rename the json file
## Install
diff --git a/drive/quickstart/quickstart.py b/drive/quickstart/quickstart.py
index f8d0cb6c..117ba4f8 100644
--- a/drive/quickstart/quickstart.py
+++ b/drive/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START drive_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,50 +22,54 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
+SCOPES = ["https://www.googleapis.com/auth/drive.metadata.readonly"]
def main():
- """Shows basic usage of the Drive v3 API.
- Prints the names and ids of the first 10 files the user has access to.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Drive v3 API.
+ Prints the names and ids of the first 10 files the user has access to.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('drive', 'v3', credentials=creds)
+ try:
+ service = build("drive", "v3", credentials=creds)
- # Call the Drive v3 API
- results = service.files().list(
- pageSize=10, fields="nextPageToken, files(id, name)").execute()
- items = results.get('files', [])
+ # Call the Drive v3 API
+ results = (
+ service.files()
+ .list(pageSize=10, fields="nextPageToken, files(id, name)")
+ .execute()
+ )
+ items = results.get("files", [])
- if not items:
- print('No files found.')
- return
- print('Files:')
- for item in items:
- print(u'{0} ({1})'.format(item['name'], item['id']))
- except HttpError as error:
- # TODO(developer) - Handle errors from drive API.
- print(f'An error occurred: {error}')
+ if not items:
+ print("No files found.")
+ return
+ print("Files:")
+ for item in items:
+ print(f"{item['name']} ({item['id']})")
+ except HttpError as error:
+ # TODO(developer) - Handle errors from drive API.
+ print(f"An error occurred: {error}")
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END drive_quickstart]
diff --git a/drive/snippets/drive-v2/app data snippet/fetch_appdata_folder.py b/drive/snippets/drive-v2/app data snippet/fetch_appdata_folder.py
new file mode 100644
index 00000000..94008a33
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/fetch_appdata_folder.py
@@ -0,0 +1,49 @@
+"""Copyright 2018 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.
+"""
+
+# [START drive_fetch_appdata_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_appdata_folder():
+ """List out application data folder and prints folder ID.
+ Returns : Folder ID
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ file = service.files().get(fileId="appDataFolder", fields="id").execute()
+ print(f'Folder ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ fetch_appdata_folder()
+# [END drive_fetch_appdata_folder]
diff --git a/drive/snippets/drive-v2/app data snippet/list_appdata.py b/drive/snippets/drive-v2/app data snippet/list_appdata.py
new file mode 100644
index 00000000..3930d30b
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/list_appdata.py
@@ -0,0 +1,60 @@
+"""Copyright 2018 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.
+"""
+
+# [START drive_list_appdata]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def list_appdata():
+ """List all files inserted in the application data folder
+ prints file titles with Ids.
+ Returns : List of items
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ response = (
+ service.files()
+ .list(
+ spaces="appDataFolder",
+ fields="nextPageToken, items(id, title)",
+ maxResults=10,
+ )
+ .execute()
+ )
+ for file in response.get("items", []):
+ # Process change
+ print(f'Found file: {file.get("title")} ,{file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ response = None
+
+ return response.get("items")
+
+
+if __name__ == "__main__":
+ list_appdata()
+# [END drive_list_appdata]
diff --git a/drive/snippets/drive-v2/app data snippet/test_fetch_appdata_folder.py b/drive/snippets/drive-v2/app data snippet/test_fetch_appdata_folder.py
new file mode 100644
index 00000000..5eddf5f8
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/test_fetch_appdata_folder.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_appdata_folder
+
+
+class TestFetchAppdataFolder(unittest.TestCase):
+ """Unit test class for Appdata snippet"""
+
+ @classmethod
+ def test_list_appdata(cls):
+ """Test list_appdata"""
+ file_id = fetch_appdata_folder.fetch_appdata_folder()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/app data snippet/test_list_appdata.py b/drive/snippets/drive-v2/app data snippet/test_list_appdata.py
new file mode 100644
index 00000000..f4a959a2
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/test_list_appdata.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import list_appdata
+
+
+class TestListAppdata(unittest.TestCase):
+ """Unit test class for Appdata snippet"""
+
+ @classmethod
+ def test_list_appdata(cls):
+ """Test list_appdata"""
+ files = list_appdata.list_appdata()
+ cls.assertNotEqual(cls, 0, len(files))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/app data snippet/test_upload_appdata.py b/drive/snippets/drive-v2/app data snippet/test_upload_appdata.py
new file mode 100644
index 00000000..e4835c35
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/test_upload_appdata.py
@@ -0,0 +1,36 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_app_data
+
+
+class TestUploadAppdata(unittest.TestCase):
+ """
+ Unit test class for Appdata snippet
+ """
+
+ @classmethod
+ def test_upload_adddata(cls):
+ """Test upload_appdata
+ create a text file titled "abc.txt" in order to pass this test
+ """
+ file_id = upload_app_data.upload_appdata()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/app data snippet/upload_app_data.py b/drive/snippets/drive-v2/app data snippet/upload_app_data.py
new file mode 100644
index 00000000..0514c07a
--- /dev/null
+++ b/drive/snippets/drive-v2/app data snippet/upload_app_data.py
@@ -0,0 +1,59 @@
+"""Copyright 2018 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.
+"""
+
+# [START drive_upload_appdata]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_appdata():
+ """Insert a file in the application data folder and prints file Id.
+ Returns : ID's of the inserted files
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_metadata = {
+ "title": "abc.txt",
+ "parents": [{"id": "appDataFolder"}],
+ }
+ media = MediaFileUpload("abc.txt", mimetype="text/txt", resumable=True)
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .insert(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_appdata()
+# [END drive_upload_appdata]
diff --git a/drive/snippets/drive-v2/change snippet/fetch_changes.py b/drive/snippets/drive-v2/change snippet/fetch_changes.py
new file mode 100644
index 00000000..904132fc
--- /dev/null
+++ b/drive/snippets/drive-v2/change snippet/fetch_changes.py
@@ -0,0 +1,62 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_fetch_changes]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_changes(saved_start_page_token):
+ """Retrieve the list of changes for the currently authenticated user.
+ prints changed file's ID
+ Args:
+ saved_start_page_token : StartPageToken for the current state of the
+ account.
+ Returns: saved start page token.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # Begin with our last saved start token for this user or the
+ # current token from getStartPageToken()
+ page_token = saved_start_page_token
+ while page_token is not None:
+ # pylint: disable=maybe-no-member
+ response = (
+ service.changes().list(pageToken=page_token, spaces="drive").execute()
+ )
+ for change in response.get("items"):
+ # Process change
+ print(f'Change found for file: {change.get("fileId")}')
+ if "newStartPageToken" in response:
+ # Last page, save this token for the next polling interval
+ saved_start_page_token = response.get("newStartPageToken")
+ page_token = response.get("nextPageToken")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ saved_start_page_token = None
+
+ return saved_start_page_token
+
+
+if __name__ == "__main__":
+ # saved_start_page_token is the token number
+ fetch_changes(saved_start_page_token=15)
+# [END drive_fetch_changes]
diff --git a/drive/snippets/drive-v2/change snippet/fetch_start_page_token.py b/drive/snippets/drive-v2/change snippet/fetch_start_page_token.py
new file mode 100644
index 00000000..9d8f16cb
--- /dev/null
+++ b/drive/snippets/drive-v2/change snippet/fetch_start_page_token.py
@@ -0,0 +1,46 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_fetch_start_page_token]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_start_page_token():
+ """Retrieve page token for the current state of the account.
+ Returns & prints : start page token
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ response = service.changes().getStartPageToken().execute()
+ print(f'Start token: {response.get("startPageToken")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ response = None
+
+ return response.get("startPageToken")
+
+
+if __name__ == "__main__":
+ fetch_start_page_token()
+# [END drive_fetch_start_page_token]
diff --git a/drive/snippets/drive-v2/change snippet/test_fetch_changes.py b/drive/snippets/drive-v2/change snippet/test_fetch_changes.py
new file mode 100644
index 00000000..adb16f2d
--- /dev/null
+++ b/drive/snippets/drive-v2/change snippet/test_fetch_changes.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_changes
+import fetch_start_page_token
+
+
+class TestFetchChanges(unittest.TestCase):
+ """Unit test class for Change snippet"""
+
+ @classmethod
+ def test_fetch_changes(cls):
+ """Test fetch_changes"""
+ start_token = fetch_start_page_token.fetch_start_page_token()
+ token = fetch_changes.fetch_changes(start_token)
+ cls.assertIsNotNone(cls, token)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/change snippet/test_fetch_start_page_token.py b/drive/snippets/drive-v2/change snippet/test_fetch_start_page_token.py
new file mode 100644
index 00000000..69b2cd15
--- /dev/null
+++ b/drive/snippets/drive-v2/change snippet/test_fetch_start_page_token.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_start_page_token
+
+
+class TestFetchChanges(unittest.TestCase):
+ """Unit test class for Change snippet"""
+
+ @classmethod
+ def test_fetch_start_page_token(cls):
+ """Test fetch_start_page_token"""
+ token = fetch_start_page_token.fetch_start_page_token()
+ cls.assertIsNotNone(cls, token)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/drive_snippet/create_drive.py b/drive/snippets/drive-v2/drive_snippet/create_drive.py
new file mode 100644
index 00000000..a5ef4de8
--- /dev/null
+++ b/drive/snippets/drive-v2/drive_snippet/create_drive.py
@@ -0,0 +1,59 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_drive]
+import uuid
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_drive():
+ """Create a drive.
+ Returns:
+ Id of the created drive
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ drive_metadata = {"name": "Project Resources"}
+ request_id = str(uuid.uuid4())
+ # pylint: disable=maybe-no-member
+ drive = (
+ service.drives()
+ .insert(body=drive_metadata, requestId=request_id, fields="id")
+ .execute()
+ )
+ print(f'Drive ID: {drive.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ drive = None
+
+ return drive.get("id")
+
+
+if __name__ == "__main__":
+ create_drive()
+# [END drive_create_drive]
diff --git a/drive/snippets/drive-v2/drive_snippet/recover_drives.py b/drive/snippets/drive-v2/drive_snippet/recover_drives.py
new file mode 100644
index 00000000..4584df3d
--- /dev/null
+++ b/drive/snippets/drive-v2/drive_snippet/recover_drives.py
@@ -0,0 +1,93 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_recover_drives]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def recover_drives(real_user):
+ """Find all shared drives without an organizer and add one.
+ Args:
+ real_user:User ID for the new organizer.
+ Returns:
+ drives object
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ drives = []
+
+ page_token = None
+ new_organizer_permission = {
+ "type": "user",
+ "role": "organizer",
+ "value": "user@example.com",
+ }
+
+ new_organizer_permission["value"] = real_user
+ # pylint: disable=maybe-no-member
+
+ while True:
+ response = (
+ service.drives()
+ .list(
+ q="organizerCount = 0",
+ useDomainAdminAccess=True,
+ fields="nextPageToken, items(id, name)",
+ pageToken=page_token,
+ )
+ .execute()
+ )
+ for drive in response.get("items", []):
+ print(
+ "Found shared drive without organizer: "
+ f"{drive.get('title')}, {drive.get('id')}"
+ )
+ permission = (
+ service.permissions()
+ .insert(
+ fileId=drive.get("id"),
+ body=new_organizer_permission,
+ useDomainAdminAccess=True,
+ supportsAllDrives=True,
+ fields="id",
+ )
+ .execute()
+ )
+ print(f'Added organizer permission: {permission.get("id")}')
+
+ drives.extend(response.get("items", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+ return drives
+
+
+if __name__ == "__main__":
+ recover_drives(real_user="gduser1@workspacesamples.dev")
+# [END drive_recover_drives]
diff --git a/drive/snippets/drive-v2/file snippet/create_folder.py b/drive/snippets/drive-v2/file snippet/create_folder.py
new file mode 100644
index 00000000..a32b24bf
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/create_folder.py
@@ -0,0 +1,53 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_folder():
+ """Create a folder and prints the folder ID
+ Returns : Folder Id
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+ file_metadata = {
+ "title": "Invoices",
+ "mimeType": "application/vnd.google-apps.folder",
+ }
+
+ # pylint: disable=maybe-no-member
+ file = service.files().insert(body=file_metadata, fields="id").execute()
+ print(f'Folder ID: "{file.get("id")}".')
+ return file.get("id")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ create_folder()
+# [END drive_create_folder]
diff --git a/drive/snippets/drive-v2/file snippet/create_shortcut.py b/drive/snippets/drive-v2/file snippet/create_shortcut.py
new file mode 100644
index 00000000..70665c09
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/create_shortcut.py
@@ -0,0 +1,50 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_shortcut]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_shortcut():
+ """Create a third party shortcut
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+ file_metadata = {
+ "title": "Project plan",
+ "mimeType": "application/vnd.google-apps.drive-sdk",
+ }
+ # pylint: disable=maybe-no-member
+ file = service.files().insert(body=file_metadata, fields="id").execute()
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ create_shortcut()
+# [END drive_create_shortcut]
diff --git a/drive/snippets/drive-v2/file snippet/download_file.py b/drive/snippets/drive-v2/file snippet/download_file.py
new file mode 100644
index 00000000..68fe2faa
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/download_file.py
@@ -0,0 +1,62 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_download_file]
+import io
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaIoBaseDownload
+
+
+def download_file(real_file_id):
+ """Downloads a file
+ Args:
+ real_file_id: ID of the file to download
+ Returns : IO object with location.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_id = real_file_id
+
+ # pylint: disable=maybe-no-member
+ request = service.files().get_media(fileId=file_id)
+ file = io.BytesIO()
+ downloader = MediaIoBaseDownload(file, request)
+ done = False
+ while done is False:
+ status, done = downloader.next_chunk()
+ print(f"Download {int(status.progress() * 100)}.")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.getvalue()
+
+
+if __name__ == "__main__":
+ download_file(real_file_id="1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9")
+# [END drive_download_file]
diff --git a/drive/snippets/drive-v2/file snippet/export_pdf.py b/drive/snippets/drive-v2/file snippet/export_pdf.py
new file mode 100644
index 00000000..cde24bf0
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/export_pdf.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_export_pdf]
+import io
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaIoBaseDownload
+
+
+def export_pdf(real_file_id):
+ """Download a Document file in PDF format.
+ Args:
+ real_file_id : file ID of any workspace document format file
+ Returns : IO object with location
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_id = real_file_id
+
+ # pylint: disable=maybe-no-member
+ request = service.files().export_media(
+ fileId=file_id, mimeType="application/pdf"
+ )
+ file = io.BytesIO()
+ downloader = MediaIoBaseDownload(file, request)
+ done = False
+ while done is False:
+ status, done = downloader.next_chunk()
+ print(f"Download {int(status.progress() * 100)}.")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.getvalue()
+
+
+if __name__ == "__main__":
+ export_pdf(real_file_id="1zbp8wAyuImX91Jt9mI-CAX_1TqkBLDEDcr2WeXBbKUY")
+# [END drive_export_pdf]
diff --git a/drive/snippets/drive-v2/file snippet/move_file_to_folder.py b/drive/snippets/drive-v2/file snippet/move_file_to_folder.py
new file mode 100644
index 00000000..a4093ce4
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/move_file_to_folder.py
@@ -0,0 +1,74 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_move_file_to_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def move_file_to_folder(file_id, folder_id):
+ """Move specified file to the specified folder.
+ Args:
+ file_id: Id of the file to move.
+ folder_id: Id of the folder
+ Print: An object containing the new parent folder and other meta data
+ Returns : Parent Ids for the file
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # Retrieve the existing parents to remove
+ # pylint: disable=maybe-no-member
+ file = service.files().get(fileId=file_id, fields="parents").execute()
+ previous_parents = ",".join(
+ [parent["id"] for parent in file.get("parents")]
+ )
+ # Move the file to the new folder
+ file = (
+ service.files()
+ .update(
+ fileId=file_id,
+ addParents=folder_id,
+ removeParents=previous_parents,
+ fields="id, parents",
+ )
+ .execute()
+ )
+ new_parent_folder_id = [parent["id"] for parent in file.get("parents")]
+ print(
+ f'file with ID : {file.get("id")} moved to folder : '
+ f"{new_parent_folder_id}"
+ )
+ return [parent["id"] for parent in file.get("parents")]
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ move_file_to_folder(
+ file_id="14fesChjgzDA7lUu9ZeGqXOuXMPgaVkxS",
+ folder_id="1KzT9gjq-AHfciwNzKjh7nUd6prrQOA4",
+ )
+# [END drive_move_file_to_folder]
diff --git a/drive/snippets/drive-v2/file snippet/search_file.py b/drive/snippets/drive-v2/file snippet/search_file.py
new file mode 100644
index 00000000..efc990d9
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/search_file.py
@@ -0,0 +1,66 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_search_file]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def search_file():
+ """Search file in drive location
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+ files = []
+ page_token = None
+ while True:
+ # pylint: disable=maybe-no-member
+ response = (
+ service.files()
+ .list(
+ q="mimeType='image/jpeg'",
+ spaces="drive",
+ fields="nextPageToken, items(id, title)",
+ pageToken=page_token,
+ )
+ .execute()
+ )
+ for file in response.get("items", []):
+ # Process change
+ print(f'Found file: {file.get("title")}, {file.get("id")}')
+ files.extend(response.get("items", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ files = None
+
+ return files
+
+
+if __name__ == "__main__":
+ search_file()
+# [END drive_search_file]
diff --git a/drive/snippets/drive-v2/file snippet/share_file.py b/drive/snippets/drive-v2/file snippet/share_file.py
new file mode 100644
index 00000000..c45a11fd
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/share_file.py
@@ -0,0 +1,94 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_share_file]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def share_file(real_file_id, real_user, real_domain):
+ """Batch permission modification.
+ Args:
+ real_file_id: file Id
+ real_user: User ID
+ real_domain: Domain of the user ID
+ Prints modified permissions
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+ ids = []
+ file_id = real_file_id
+
+ def callback(request_id, response, exception):
+ if exception:
+ print(exception)
+ else:
+ print(f"Request_Id: {request_id}")
+ print(f'Permission Id: {response.get("id")}')
+ ids.append(response.get("id"))
+
+ # pylint: disable=maybe-no-member
+ batch = service.new_batch_http_request(callback=callback)
+ user_permission = {
+ "type": "user",
+ "role": "writer",
+ "value": "user@example.com",
+ }
+ user_permission["value"] = real_user
+ batch.add(
+ service.permissions().insert(
+ fileId=file_id,
+ body=user_permission,
+ fields="id",
+ )
+ )
+ domain_permission = {
+ "type": "domain",
+ "role": "reader",
+ "value": "example.com",
+ }
+ domain_permission["value"] = real_domain
+ batch.add(
+ service.permissions().insert(
+ fileId=file_id,
+ body=domain_permission,
+ fields="id",
+ )
+ )
+ batch.execute()
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ ids = None
+
+ return ids
+
+
+if __name__ == "__main__":
+ share_file(
+ real_file_id="1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l",
+ real_user="anurag@workspacesamples.dev",
+ real_domain="workspacesamples.dev",
+ )
+# [END drive_share_file]
diff --git a/drive/snippets/drive-v2/file snippet/test_create_folder.py b/drive/snippets/drive-v2/file snippet/test_create_folder.py
new file mode 100644
index 00000000..24eb83d0
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_create_folder.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import create_folder
+
+
+class TestCreateFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_create_folder(cls):
+ """Test create_folder"""
+ file_id = create_folder.create_folder()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_create_shortcut.py b/drive/snippets/drive-v2/file snippet/test_create_shortcut.py
new file mode 100644
index 00000000..82789471
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_create_shortcut.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import create_shortcut
+
+
+class TestCreateShortcut(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_create_shortcut(cls):
+ """Test create_folder"""
+ file_id = create_shortcut.create_shortcut()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_download_file.py b/drive/snippets/drive-v2/file snippet/test_download_file.py
new file mode 100644
index 00000000..bb5455bd
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_download_file.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import download_file
+
+
+class TestDownloadFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_download_file(cls):
+ """Test Download_file"""
+ # valid file id
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ file = download_file.download_file(real_file_id=real_file_id)
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_export_pdf.py b/drive/snippets/drive-v2/file snippet/test_export_pdf.py
new file mode 100644
index 00000000..e9dfb88f
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_export_pdf.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import export_pdf
+
+
+class TestExportPdf(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_export_pdf(cls):
+ """Test export_pdf"""
+ # valid file ID
+ real_file_id = "1zbp8wAyuImX91Jt9mI-CAX_1TqkBLDEDcr2WeXBbKUY"
+ file = export_pdf.export_pdf(real_file_id=real_file_id)
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_move_file_to_folder.py b/drive/snippets/drive-v2/file snippet/test_move_file_to_folder.py
new file mode 100644
index 00000000..b031b13c
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_move_file_to_folder.py
@@ -0,0 +1,37 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import move_file_to_folder
+
+
+class TestMoveFileToFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_move_file_to_folder(cls):
+ """Test move_file_to_folder"""
+ file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ folder_id = "1v5eyIbXCr9TZX3eX_44HEExfe7yRj24V"
+
+ update = move_file_to_folder.move_file_to_folder(
+ file_id=file_id, folder_id=folder_id
+ )
+ cls.assertIsNotNone(cls, 0, len(update))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_search_file.py b/drive/snippets/drive-v2/file snippet/test_search_file.py
new file mode 100644
index 00000000..a86d2158
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_search_file.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import search_file
+
+
+class TestSearchFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_search_file(cls):
+ """Test search_file"""
+ file = search_file.search_file()
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_share_file.py b/drive/snippets/drive-v2/file snippet/test_share_file.py
new file mode 100644
index 00000000..4c281998
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_share_file.py
@@ -0,0 +1,39 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import share_file
+
+
+class TestShareFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_share_file(cls):
+ """Test share_file"""
+ real_file_id = "1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l"
+ real_user = "gduser1@workspacesamples.dev"
+ real_domain = "workspacesamples.dev"
+ file = share_file.share_file(
+ real_file_id=real_file_id,
+ real_user=real_user,
+ real_domain=real_domain,
+ )
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_touch_file.py b/drive/snippets/drive-v2/file snippet/test_touch_file.py
new file mode 100644
index 00000000..f35dc08d
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_touch_file.py
@@ -0,0 +1,39 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import re
+import unittest
+from datetime import datetime
+
+import touch_file
+
+
+class TestTouchFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_touch_file(cls):
+ """Test touch_file"""
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ now = datetime.utcnow().isoformat() + "Z"
+ now = re.sub(r"\d{3}Z", "Z", now) # Truncate microseconds
+ modified_time = touch_file.touch_file(
+ real_file_id=real_file_id, real_timestamp=now
+ )
+ cls.assertIsNotNone(cls, modified_time)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_upload_basic.py b/drive/snippets/drive-v2/file snippet/test_upload_basic.py
new file mode 100644
index 00000000..c0bb7c30
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_upload_basic.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_basic
+
+
+class TestUploadBasic(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_basic(cls):
+ """Test upload_basic"""
+ file_id = upload_basic.upload_basic()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_upload_revision.py b/drive/snippets/drive-v2/file snippet/test_upload_revision.py
new file mode 100644
index 00000000..c1ab5a6d
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_upload_revision.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_revision
+
+
+class TestUploadRevision(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_revision(cls):
+ """Test upload_revision"""
+
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ file_id = upload_revision.upload_revision(real_file_id=real_file_id)
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_upload_to_folder.py b/drive/snippets/drive-v2/file snippet/test_upload_to_folder.py
new file mode 100644
index 00000000..82a314cf
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_upload_to_folder.py
@@ -0,0 +1,33 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_to_folder
+
+
+class TestUploadToFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_to_folder(cls):
+ """Test upload_to_folder"""
+ folder_id = "1s0oKEZZXjImNngxHGnY0xed6Mw-tvspu"
+ file_id = upload_to_folder.upload_to_folder(folder_id=folder_id)
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/test_upload_with_conversion.py b/drive/snippets/drive-v2/file snippet/test_upload_with_conversion.py
new file mode 100644
index 00000000..ce3bd168
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/test_upload_with_conversion.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_with_conversion
+
+
+class TestUploadWithConversion(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_to_folder(cls):
+ """Test upload_with_conversion"""
+ file_id = upload_with_conversion.upload_with_conversion()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v2/file snippet/touch_file.py b/drive/snippets/drive-v2/file snippet/touch_file.py
new file mode 100644
index 00000000..8369b274
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/touch_file.py
@@ -0,0 +1,71 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_touch_file]
+from datetime import datetime
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def touch_file(real_file_id, real_timestamp):
+ """Change the file's modification timestamp.
+ Args:
+ real_file_id: ID of the file to change modified time
+ real_timestamp: Timestamp to override Modified date time of the file
+ Returns : Modified Date and time.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_metadata = {"modifiedDate": datetime.utcnow().isoformat() + "Z"}
+
+ file_id = real_file_id
+ file_metadata["modifiedDate"] = real_timestamp
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .update(
+ fileId=file_id,
+ body=file_metadata,
+ setModifiedDate=True,
+ fields="id, modifiedDate",
+ )
+ .execute()
+ )
+ print(f'Modified time: {file.get("modifiedDate")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("modifiedDate")
+
+
+if __name__ == "__main__":
+ touch_file(
+ real_file_id="1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9",
+ real_timestamp="2022-03-02T05:43:27.504Z",
+ )
+# [END drive_touch_file]
diff --git a/drive/snippets/drive-v2/file snippet/upload_basic.py b/drive/snippets/drive-v2/file snippet/upload_basic.py
new file mode 100644
index 00000000..2821ed9d
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/upload_basic.py
@@ -0,0 +1,57 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_basic]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_basic():
+ """Insert new file.
+ Returns : Id's of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_metadata = {"title": "photo.jpg"}
+ media = MediaFileUpload("photo.jpg", mimetype="image/jpeg")
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .insert(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_basic()
+# [END drive_upload_basic]
diff --git a/drive/snippets/drive-v2/file snippet/upload_revision.py b/drive/snippets/drive-v2/file snippet/upload_revision.py
new file mode 100644
index 00000000..7cce8f5a
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/upload_revision.py
@@ -0,0 +1,56 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_revision]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_revision(real_file_id):
+ """Replace the old file with new one on same file ID
+ Args: ID of the file to be replaced
+ Returns: file ID
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+ file_id = real_file_id
+ media = MediaFileUpload("photo.jpg", mimetype="image/jpeg", resumable=True)
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .update(fileId=file_id, body={}, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_revision(real_file_id="1M4xjYwPynOk5TsIWN7hcGYkFdBkPTd5F")
+# [END drive_upload_revision]
diff --git a/drive/snippets/drive-v2/file snippet/upload_to_folder.py b/drive/snippets/drive-v2/file snippet/upload_to_folder.py
new file mode 100644
index 00000000..4b9a5179
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/upload_to_folder.py
@@ -0,0 +1,57 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_to_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_to_folder(folder_id):
+ """Upload a file to the specified folder and prints file ID, folder ID
+ Args: Id of the folder
+ Returns: ID of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_metadata = {"title": "photo.jpg", "parents": [{"id": folder_id}]}
+ media = MediaFileUpload("photo.jpg", mimetype="image/jpeg", resumable=True)
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .insert(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: "{file.get("id")}".')
+ return file.get("id")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ upload_to_folder(folder_id="1s0oKEZZXjImNngxHGnY0xed6Mw-tvspu")
+# [END drive_upload_to_folder]
diff --git a/drive/snippets/drive-v2/file snippet/upload_with_conversion.py b/drive/snippets/drive-v2/file snippet/upload_with_conversion.py
new file mode 100644
index 00000000..1e010f67
--- /dev/null
+++ b/drive/snippets/drive-v2/file snippet/upload_with_conversion.py
@@ -0,0 +1,60 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_with_conversion]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_with_conversion():
+ """Upload file with conversion
+ Returns: ID of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ file_metadata = {
+ "title": "My Report",
+ "mimeType": "application/vnd.google-apps.spreadsheet",
+ }
+ media = MediaFileUpload("report.csv", mimetype="text/csv", resumable=True)
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .insert(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File with ID: "{file.get("id")}" has been uploaded.')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_with_conversion()
+# [END drive_upload_with_conversion]
diff --git a/drive/snippets/drive-v2/team_drive_snippets/create_team_drive.py b/drive/snippets/drive-v2/team_drive_snippets/create_team_drive.py
new file mode 100644
index 00000000..1c1b1a79
--- /dev/null
+++ b/drive/snippets/drive-v2/team_drive_snippets/create_team_drive.py
@@ -0,0 +1,57 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_create_team_drive]
+import uuid
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_team_drive():
+ """Create a drive for team.
+ Returns: ID of the created drive
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ team_drive_metadata = {"name": "Project Resources"}
+ request_id = str(uuid.uuid4())
+ team_drive = (
+ service.teamdrives()
+ .insert(body=team_drive_metadata, requestId=request_id, fields="id")
+ .execute()
+ )
+ print(f'Team Drive ID: {team_drive.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ team_drive = None
+
+ return team_drive.get("id")
+
+
+if __name__ == "__main__":
+ create_team_drive()
+# [END drive_create_team_drive]
diff --git a/drive/snippets/drive-v2/team_drive_snippets/recover_team_drives.py b/drive/snippets/drive-v2/team_drive_snippets/recover_team_drives.py
new file mode 100644
index 00000000..150f9710
--- /dev/null
+++ b/drive/snippets/drive-v2/team_drive_snippets/recover_team_drives.py
@@ -0,0 +1,93 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_recover_team_drives]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def recover_team_drives(real_user):
+ """Finds all Team Drives without an organizer and add one
+ Args:
+ real_user:User ID for the new organizer.
+ Returns:
+ team drives_object.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v2", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ team_drives = []
+
+ page_token = None
+ new_organizer_permission = {
+ "type": "user",
+ "role": "organizer",
+ "value": "user@example.com",
+ }
+ new_organizer_permission["value"] = real_user
+
+ while True:
+ response = (
+ service.teamdrives()
+ .list(
+ q="organizerCount = 0",
+ useDomainAdminAccess=True,
+ fields="nextPageToken, items(id, name)",
+ pageToken=page_token,
+ )
+ .execute()
+ )
+ for team_drive in response.get("items", []):
+ print(
+ "Found Team Drive without organizer: "
+ f"{team_drive.get('title')}, {team_drive.get('id')}"
+ )
+ permission = (
+ service.permissions()
+ .insert(
+ fileId=team_drive.get("id"),
+ body=new_organizer_permission,
+ useDomainAdminAccess=True,
+ supportsTeamDrives=True,
+ fields="id",
+ )
+ .execute()
+ )
+ print(f'Added organizer permission: {permission.get("id")}')
+
+ team_drives.extend(response.get("items", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ team_drives = None
+
+ print(team_drives)
+
+
+if __name__ == "__main__":
+ recover_team_drives(real_user="rajesh@workspacesamples.dev")
+# [END drive_recover_team_drives]
diff --git a/drive/snippets/drive-v3/app_data_snippet/fetch_appdata_folder.py b/drive/snippets/drive-v3/app_data_snippet/fetch_appdata_folder.py
new file mode 100644
index 00000000..2cfa9117
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/fetch_appdata_folder.py
@@ -0,0 +1,49 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_fetch_appdata_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_appdata_folder():
+ """List out application data folder and prints folder ID.
+ Returns : Folder ID
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ file = service.files().get(fileId="appDataFolder", fields="id").execute()
+ print(f'Folder ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ fetch_appdata_folder()
+# [END drive_fetch_appdata_folder]
diff --git a/drive/snippets/drive-v3/app_data_snippet/list_appdata.py b/drive/snippets/drive-v3/app_data_snippet/list_appdata.py
new file mode 100644
index 00000000..e69fe22a
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/list_appdata.py
@@ -0,0 +1,60 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_list_appdata]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def list_appdata():
+ """List all files inserted in the application data folder
+ prints file titles with Ids.
+ Returns : List of items
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ response = (
+ service.files()
+ .list(
+ spaces="appDataFolder",
+ fields="nextPageToken, files(id, name)",
+ pageSize=10,
+ )
+ .execute()
+ )
+ for file in response.get("files", []):
+ # Process change
+ print(f'Found file: {file.get("name")}, {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ response = None
+
+ return response.get("files")
+
+
+if __name__ == "__main__":
+ list_appdata()
+# [END drive_list_appdata]
diff --git a/drive/snippets/drive-v3/app_data_snippet/test_fetch_appdata_folder.py b/drive/snippets/drive-v3/app_data_snippet/test_fetch_appdata_folder.py
new file mode 100644
index 00000000..5eddf5f8
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/test_fetch_appdata_folder.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_appdata_folder
+
+
+class TestFetchAppdataFolder(unittest.TestCase):
+ """Unit test class for Appdata snippet"""
+
+ @classmethod
+ def test_list_appdata(cls):
+ """Test list_appdata"""
+ file_id = fetch_appdata_folder.fetch_appdata_folder()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/app_data_snippet/test_list_appdata.py b/drive/snippets/drive-v3/app_data_snippet/test_list_appdata.py
new file mode 100644
index 00000000..f4a959a2
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/test_list_appdata.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import list_appdata
+
+
+class TestListAppdata(unittest.TestCase):
+ """Unit test class for Appdata snippet"""
+
+ @classmethod
+ def test_list_appdata(cls):
+ """Test list_appdata"""
+ files = list_appdata.list_appdata()
+ cls.assertNotEqual(cls, 0, len(files))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/app_data_snippet/test_upload_appdata.py b/drive/snippets/drive-v3/app_data_snippet/test_upload_appdata.py
new file mode 100644
index 00000000..e4835c35
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/test_upload_appdata.py
@@ -0,0 +1,36 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_app_data
+
+
+class TestUploadAppdata(unittest.TestCase):
+ """
+ Unit test class for Appdata snippet
+ """
+
+ @classmethod
+ def test_upload_adddata(cls):
+ """Test upload_appdata
+ create a text file titled "abc.txt" in order to pass this test
+ """
+ file_id = upload_app_data.upload_appdata()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/app_data_snippet/upload_appdata.py b/drive/snippets/drive-v3/app_data_snippet/upload_appdata.py
new file mode 100644
index 00000000..c35f3e66
--- /dev/null
+++ b/drive/snippets/drive-v3/app_data_snippet/upload_appdata.py
@@ -0,0 +1,56 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_upload_appdata]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_appdata():
+ """Insert a file in the application data folder and prints file Id.
+ Returns : ID's of the inserted files
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ file_metadata = {"name": "abc.txt", "parents": ["appDataFolder"]}
+ media = MediaFileUpload("abc.txt", mimetype="text/txt", resumable=True)
+ file = (
+ service.files()
+ .create(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_appdata()
+# [END drive_upload_appdata]
diff --git a/drive/snippets/drive-v3/change_snippet/fetch_changes.py b/drive/snippets/drive-v3/change_snippet/fetch_changes.py
new file mode 100644
index 00000000..d6809e51
--- /dev/null
+++ b/drive/snippets/drive-v3/change_snippet/fetch_changes.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_fetch_changes]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_changes(saved_start_page_token):
+ """Retrieve the list of changes for the currently authenticated user.
+ prints changed file's ID
+ Args:
+ saved_start_page_token : StartPageToken for the current state of the
+ account.
+ Returns: saved start page token.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # Begin with our last saved start token for this user or the
+ # current token from getStartPageToken()
+ page_token = saved_start_page_token
+ # pylint: disable=maybe-no-member
+
+ while page_token is not None:
+ response = (
+ service.changes().list(pageToken=page_token, spaces="drive").execute()
+ )
+ for change in response.get("changes"):
+ # Process change
+ print(f'Change found for file: {change.get("fileId")}')
+ if "newStartPageToken" in response:
+ # Last page, save this token for the next polling interval
+ saved_start_page_token = response.get("newStartPageToken")
+ page_token = response.get("nextPageToken")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ saved_start_page_token = None
+
+ return saved_start_page_token
+
+
+if __name__ == "__main__":
+ # saved_start_page_token is the token number
+ fetch_changes(saved_start_page_token=209)
+# [END drive_fetch_changes]
diff --git a/drive/snippets/drive-v3/change_snippet/fetch_start_page_token.py b/drive/snippets/drive-v3/change_snippet/fetch_start_page_token.py
new file mode 100644
index 00000000..df36b35a
--- /dev/null
+++ b/drive/snippets/drive-v3/change_snippet/fetch_start_page_token.py
@@ -0,0 +1,47 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_fetch_start_page_token]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def fetch_start_page_token():
+ """Retrieve page token for the current state of the account.
+ Returns & prints : start page token
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ response = service.changes().getStartPageToken().execute()
+ print(f'Start token: {response.get("startPageToken")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ response = None
+
+ return response.get("startPageToken")
+
+
+if __name__ == "__main__":
+ fetch_start_page_token()
+# [END drive_fetch_start_page_token]
diff --git a/drive/snippets/drive-v3/change_snippet/test_fetch_changes.py b/drive/snippets/drive-v3/change_snippet/test_fetch_changes.py
new file mode 100644
index 00000000..adb16f2d
--- /dev/null
+++ b/drive/snippets/drive-v3/change_snippet/test_fetch_changes.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_changes
+import fetch_start_page_token
+
+
+class TestFetchChanges(unittest.TestCase):
+ """Unit test class for Change snippet"""
+
+ @classmethod
+ def test_fetch_changes(cls):
+ """Test fetch_changes"""
+ start_token = fetch_start_page_token.fetch_start_page_token()
+ token = fetch_changes.fetch_changes(start_token)
+ cls.assertIsNotNone(cls, token)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/change_snippet/test_fetch_start_page_token.py b/drive/snippets/drive-v3/change_snippet/test_fetch_start_page_token.py
new file mode 100644
index 00000000..69b2cd15
--- /dev/null
+++ b/drive/snippets/drive-v3/change_snippet/test_fetch_start_page_token.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import fetch_start_page_token
+
+
+class TestFetchChanges(unittest.TestCase):
+ """Unit test class for Change snippet"""
+
+ @classmethod
+ def test_fetch_start_page_token(cls):
+ """Test fetch_start_page_token"""
+ token = fetch_start_page_token.fetch_start_page_token()
+ cls.assertIsNotNone(cls, token)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/drive_snippet/create_drive.py b/drive/snippets/drive-v3/drive_snippet/create_drive.py
new file mode 100644
index 00000000..871a495f
--- /dev/null
+++ b/drive/snippets/drive-v3/drive_snippet/create_drive.py
@@ -0,0 +1,59 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_drive]
+import uuid
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_drive():
+ """Create a drive.
+ Returns:
+ Id of the created drive
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ drive_metadata = {"name": "Project Resources"}
+ request_id = str(uuid.uuid4())
+ # pylint: disable=maybe-no-member
+ drive = (
+ service.drives()
+ .create(body=drive_metadata, requestId=request_id, fields="id")
+ .execute()
+ )
+ print(f'Drive ID: {drive.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ drive = None
+
+ return drive.get("id")
+
+
+if __name__ == "__main__":
+ create_drive()
+# [END drive_create_drive]
diff --git a/drive/snippets/drive-v3/drive_snippet/recover_drives.py b/drive/snippets/drive-v3/drive_snippet/recover_drives.py
new file mode 100644
index 00000000..2f1159c7
--- /dev/null
+++ b/drive/snippets/drive-v3/drive_snippet/recover_drives.py
@@ -0,0 +1,92 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_recover_drives]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def recover_drives(real_user):
+ """Find all shared drives without an organizer and add one.
+ Args:
+ real_user:User ID for the new organizer.
+ Returns:
+ drives object
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ drives = []
+
+ # pylint: disable=maybe-no-member
+ page_token = None
+ new_organizer_permission = {
+ "type": "user",
+ "role": "organizer",
+ "emailAddress": "user@example.com",
+ }
+ new_organizer_permission["emailAddress"] = real_user
+
+ while True:
+ response = (
+ service.drives()
+ .list(
+ q="organizerCount = 0",
+ fields="nextPageToken, drives(id, name)",
+ useDomainAdminAccess=True,
+ pageToken=page_token,
+ )
+ .execute()
+ )
+ for drive in response.get("drives", []):
+ print(
+ "Found shared drive without organizer: "
+ f"{drive.get('title')}, {drive.get('id')}"
+ )
+ permission = (
+ service.permissions()
+ .create(
+ fileId=drive.get("id"),
+ body=new_organizer_permission,
+ useDomainAdminAccess=True,
+ supportsAllDrives=True,
+ fields="id",
+ )
+ .execute()
+ )
+ print(f'Added organizer permission: {permission.get("id")}')
+
+ drives.extend(response.get("drives", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+ return drives
+
+
+if __name__ == "__main__":
+ recover_drives(real_user="gduser1@workspacesamples.dev")
+# [END drive_recover_drives]
diff --git a/drive/snippets/drive-v3/file_snippet/create_folder.py b/drive/snippets/drive-v3/file_snippet/create_folder.py
new file mode 100644
index 00000000..b0fc814e
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/create_folder.py
@@ -0,0 +1,53 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_folder():
+ """Create a folder and prints the folder ID
+ Returns : Folder Id
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+ file_metadata = {
+ "name": "Invoices",
+ "mimeType": "application/vnd.google-apps.folder",
+ }
+
+ # pylint: disable=maybe-no-member
+ file = service.files().create(body=file_metadata, fields="id").execute()
+ print(f'Folder ID: "{file.get("id")}".')
+ return file.get("id")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ create_folder()
+# [END drive_create_folder]
diff --git a/drive/snippets/drive-v3/file_snippet/create_shortcut.py b/drive/snippets/drive-v3/file_snippet/create_shortcut.py
new file mode 100644
index 00000000..435b7b4d
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/create_shortcut.py
@@ -0,0 +1,51 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_create_shortcut]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_shortcut():
+ """Create a third party shortcut
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+ file_metadata = {
+ "name": "Project plan",
+ "mimeType": "application/vnd.google-apps.drive-sdk",
+ }
+
+ # pylint: disable=maybe-no-member
+ file = service.files().create(body=file_metadata, fields="id").execute()
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ create_shortcut()
+# [END drive_create_shortcut]
diff --git a/drive/snippets/drive-v3/file_snippet/download_file.py b/drive/snippets/drive-v3/file_snippet/download_file.py
new file mode 100644
index 00000000..c0345524
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/download_file.py
@@ -0,0 +1,62 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_download_file]
+import io
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaIoBaseDownload
+
+
+def download_file(real_file_id):
+ """Downloads a file
+ Args:
+ real_file_id: ID of the file to download
+ Returns : IO object with location.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_id = real_file_id
+
+ # pylint: disable=maybe-no-member
+ request = service.files().get_media(fileId=file_id)
+ file = io.BytesIO()
+ downloader = MediaIoBaseDownload(file, request)
+ done = False
+ while done is False:
+ status, done = downloader.next_chunk()
+ print(f"Download {int(status.progress() * 100)}.")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.getvalue()
+
+
+if __name__ == "__main__":
+ download_file(real_file_id="1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9")
+# [END drive_download_file]
diff --git a/drive/snippets/drive-v3/file_snippet/export_pdf.py b/drive/snippets/drive-v3/file_snippet/export_pdf.py
new file mode 100644
index 00000000..4588cbbf
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/export_pdf.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_export_pdf]
+import io
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaIoBaseDownload
+
+
+def export_pdf(real_file_id):
+ """Download a Document file in PDF format.
+ Args:
+ real_file_id : file ID of any workspace document format file
+ Returns : IO object with location
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_id = real_file_id
+
+ # pylint: disable=maybe-no-member
+ request = service.files().export_media(
+ fileId=file_id, mimeType="application/pdf"
+ )
+ file = io.BytesIO()
+ downloader = MediaIoBaseDownload(file, request)
+ done = False
+ while done is False:
+ status, done = downloader.next_chunk()
+ print(f"Download {int(status.progress() * 100)}.")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.getvalue()
+
+
+if __name__ == "__main__":
+ export_pdf(real_file_id="1zbp8wAyuImX91Jt9mI-CAX_1TqkBLDEDcr2WeXBbKUY")
+# [END drive_export_pdf]
diff --git a/drive/snippets/drive-v3/file_snippet/move_file_to_folder.py b/drive/snippets/drive-v3/file_snippet/move_file_to_folder.py
new file mode 100644
index 00000000..5d3a0a28
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/move_file_to_folder.py
@@ -0,0 +1,67 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_move_file_to_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def move_file_to_folder(file_id, folder_id):
+ """Move specified file to the specified folder.
+ Args:
+ file_id: Id of the file to move.
+ folder_id: Id of the folder
+ Print: An object containing the new parent folder and other meta data
+ Returns : Parent Ids for the file
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ # Retrieve the existing parents to remove
+ file = service.files().get(fileId=file_id, fields="parents").execute()
+ previous_parents = ",".join(file.get("parents"))
+ # Move the file to the new folder
+ file = (
+ service.files()
+ .update(
+ fileId=file_id,
+ addParents=folder_id,
+ removeParents=previous_parents,
+ fields="id, parents",
+ )
+ .execute()
+ )
+ return file.get("parents")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ move_file_to_folder(
+ file_id="1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9",
+ folder_id="1jvTFoyBhUspwDncOTB25kb9k0Fl0EqeN",
+ )
+# [END drive_move_file_to_folder]
diff --git a/drive/snippets/drive-v3/file_snippet/search_file.py b/drive/snippets/drive-v3/file_snippet/search_file.py
new file mode 100644
index 00000000..fc17b006
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/search_file.py
@@ -0,0 +1,66 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_search_file]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def search_file():
+ """Search file in drive location
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+ files = []
+ page_token = None
+ while True:
+ # pylint: disable=maybe-no-member
+ response = (
+ service.files()
+ .list(
+ q="mimeType='image/jpeg'",
+ spaces="drive",
+ fields="nextPageToken, files(id, name)",
+ pageToken=page_token,
+ )
+ .execute()
+ )
+ for file in response.get("files", []):
+ # Process change
+ print(f'Found file: {file.get("name")}, {file.get("id")}')
+ files.extend(response.get("files", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ files = None
+
+ return files
+
+
+if __name__ == "__main__":
+ search_file()
+# [END drive_search_file]
diff --git a/drive/snippets/drive-v3/file_snippet/share_file.py b/drive/snippets/drive-v3/file_snippet/share_file.py
new file mode 100644
index 00000000..8850aa5e
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/share_file.py
@@ -0,0 +1,97 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_share_file]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def share_file(real_file_id, real_user, real_domain):
+ """Batch permission modification.
+ Args:
+ real_file_id: file Id
+ real_user: User ID
+ real_domain: Domain of the user ID
+ Prints modified permissions
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+ ids = []
+ file_id = real_file_id
+
+ def callback(request_id, response, exception):
+ if exception:
+ # Handle error
+ print(exception)
+ else:
+ print(f"Request_Id: {request_id}")
+ print(f'Permission Id: {response.get("id")}')
+ ids.append(response.get("id"))
+
+ # pylint: disable=maybe-no-member
+ batch = service.new_batch_http_request(callback=callback)
+ user_permission = {
+ "type": "user",
+ "role": "writer",
+ "emailAddress": "user@example.com",
+ }
+ # [START_EXCLUDE silent]
+ user_permission["emailAddress"] = real_user
+ # [END_EXCLUDE]
+ batch.add(
+ service.permissions().create(
+ fileId=file_id,
+ body=user_permission,
+ fields="id",
+ )
+ )
+ domain_permission = {
+ "type": "domain",
+ "role": "reader",
+ "domain": "example.com",
+ }
+ domain_permission["domain"] = real_domain
+ batch.add(
+ service.permissions().create(
+ fileId=file_id,
+ body=domain_permission,
+ fields="id",
+ )
+ )
+ batch.execute()
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ ids = None
+
+ return ids
+
+
+if __name__ == "__main__":
+ share_file(
+ real_file_id="1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l",
+ real_user="gduser1@workspacesamples.dev",
+ real_domain="workspacesamples.dev",
+ )
+# [END drive_share_file]
diff --git a/drive/snippets/drive-v3/file_snippet/test_create_folder.py b/drive/snippets/drive-v3/file_snippet/test_create_folder.py
new file mode 100644
index 00000000..24eb83d0
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_create_folder.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import create_folder
+
+
+class TestCreateFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_create_folder(cls):
+ """Test create_folder"""
+ file_id = create_folder.create_folder()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_create_shortcut.py b/drive/snippets/drive-v3/file_snippet/test_create_shortcut.py
new file mode 100644
index 00000000..82789471
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_create_shortcut.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import create_shortcut
+
+
+class TestCreateShortcut(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_create_shortcut(cls):
+ """Test create_folder"""
+ file_id = create_shortcut.create_shortcut()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_download_file.py b/drive/snippets/drive-v3/file_snippet/test_download_file.py
new file mode 100644
index 00000000..bb5455bd
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_download_file.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import download_file
+
+
+class TestDownloadFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_download_file(cls):
+ """Test Download_file"""
+ # valid file id
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ file = download_file.download_file(real_file_id=real_file_id)
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_export_pdf.py b/drive/snippets/drive-v3/file_snippet/test_export_pdf.py
new file mode 100644
index 00000000..e9dfb88f
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_export_pdf.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import export_pdf
+
+
+class TestExportPdf(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_export_pdf(cls):
+ """Test export_pdf"""
+ # valid file ID
+ real_file_id = "1zbp8wAyuImX91Jt9mI-CAX_1TqkBLDEDcr2WeXBbKUY"
+ file = export_pdf.export_pdf(real_file_id=real_file_id)
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_move_file_to_folder.py b/drive/snippets/drive-v3/file_snippet/test_move_file_to_folder.py
new file mode 100644
index 00000000..b031b13c
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_move_file_to_folder.py
@@ -0,0 +1,37 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import move_file_to_folder
+
+
+class TestMoveFileToFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_move_file_to_folder(cls):
+ """Test move_file_to_folder"""
+ file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ folder_id = "1v5eyIbXCr9TZX3eX_44HEExfe7yRj24V"
+
+ update = move_file_to_folder.move_file_to_folder(
+ file_id=file_id, folder_id=folder_id
+ )
+ cls.assertIsNotNone(cls, 0, len(update))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_search_file.py b/drive/snippets/drive-v3/file_snippet/test_search_file.py
new file mode 100644
index 00000000..a86d2158
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_search_file.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import search_file
+
+
+class TestSearchFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_search_file(cls):
+ """Test search_file"""
+ file = search_file.search_file()
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_share_file.py b/drive/snippets/drive-v3/file_snippet/test_share_file.py
new file mode 100644
index 00000000..4c281998
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_share_file.py
@@ -0,0 +1,39 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import share_file
+
+
+class TestShareFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_share_file(cls):
+ """Test share_file"""
+ real_file_id = "1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l"
+ real_user = "gduser1@workspacesamples.dev"
+ real_domain = "workspacesamples.dev"
+ file = share_file.share_file(
+ real_file_id=real_file_id,
+ real_user=real_user,
+ real_domain=real_domain,
+ )
+ cls.assertNotEqual(cls, 0, len(file))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_touch_file.py b/drive/snippets/drive-v3/file_snippet/test_touch_file.py
new file mode 100644
index 00000000..f35dc08d
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_touch_file.py
@@ -0,0 +1,39 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import re
+import unittest
+from datetime import datetime
+
+import touch_file
+
+
+class TestTouchFile(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_touch_file(cls):
+ """Test touch_file"""
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ now = datetime.utcnow().isoformat() + "Z"
+ now = re.sub(r"\d{3}Z", "Z", now) # Truncate microseconds
+ modified_time = touch_file.touch_file(
+ real_file_id=real_file_id, real_timestamp=now
+ )
+ cls.assertIsNotNone(cls, modified_time)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_upload_basic.py b/drive/snippets/drive-v3/file_snippet/test_upload_basic.py
new file mode 100644
index 00000000..c0bb7c30
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_upload_basic.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_basic
+
+
+class TestUploadBasic(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_basic(cls):
+ """Test upload_basic"""
+ file_id = upload_basic.upload_basic()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_upload_revision.py b/drive/snippets/drive-v3/file_snippet/test_upload_revision.py
new file mode 100644
index 00000000..c1ab5a6d
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_upload_revision.py
@@ -0,0 +1,34 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_revision
+
+
+class TestUploadRevision(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_revision(cls):
+ """Test upload_revision"""
+
+ real_file_id = "1KuPmvGq8yoYgbfW74OENMCB5H0n_2Jm9"
+ file_id = upload_revision.upload_revision(real_file_id=real_file_id)
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_upload_to_folder.py b/drive/snippets/drive-v3/file_snippet/test_upload_to_folder.py
new file mode 100644
index 00000000..82a314cf
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_upload_to_folder.py
@@ -0,0 +1,33 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_to_folder
+
+
+class TestUploadToFolder(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_to_folder(cls):
+ """Test upload_to_folder"""
+ folder_id = "1s0oKEZZXjImNngxHGnY0xed6Mw-tvspu"
+ file_id = upload_to_folder.upload_to_folder(folder_id=folder_id)
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/test_upload_with_conversion.py b/drive/snippets/drive-v3/file_snippet/test_upload_with_conversion.py
new file mode 100644
index 00000000..ce3bd168
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/test_upload_with_conversion.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import upload_with_conversion
+
+
+class TestUploadWithConversion(unittest.TestCase):
+ """Unit test class for file snippet"""
+
+ @classmethod
+ def test_upload_to_folder(cls):
+ """Test upload_with_conversion"""
+ file_id = upload_with_conversion.upload_with_conversion()
+ cls.assertIsNotNone(cls, file_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/drive/snippets/drive-v3/file_snippet/touch_file.py b/drive/snippets/drive-v3/file_snippet/touch_file.py
new file mode 100644
index 00000000..c27ec382
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/touch_file.py
@@ -0,0 +1,65 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_touch_file]
+from datetime import datetime
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def touch_file(real_file_id, real_timestamp):
+ """Change the file's modification timestamp.
+ Args:
+ real_file_id: ID of the file to change modified time
+ real_timestamp: Timestamp to override Modified date time of the file
+ Returns : Modified Date and time.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_metadata = {"modifiedTime": datetime.utcnow().isoformat() + "Z"}
+ # pylint: disable=maybe-no-member
+ file_id = real_file_id
+ file_metadata["modifiedTime"] = real_timestamp
+ file = (
+ service.files()
+ .update(fileId=file_id, body=file_metadata, fields="id, modifiedTime")
+ .execute()
+ )
+ print(f'Modified time: {file.get("modifiedTime")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("modifiedDate")
+
+
+if __name__ == "__main__":
+ touch_file(
+ real_file_id="17EqlSf7FpPU95SS00sICyVzQHpeET1cz",
+ real_timestamp="2022-03-02T05:43:27.504Z",
+ )
+# [END drive_touch_file]
diff --git a/drive/snippets/drive-v3/file_snippet/upload_basic.py b/drive/snippets/drive-v3/file_snippet/upload_basic.py
new file mode 100644
index 00000000..1795c4d8
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/upload_basic.py
@@ -0,0 +1,57 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_basic]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_basic():
+ """Insert new file.
+ Returns : Id's of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_metadata = {"name": "download.jpeg"}
+ media = MediaFileUpload("download.jpeg", mimetype="image/jpeg")
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .create(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_basic()
+# [END drive_upload_basic]
diff --git a/drive/snippets/drive-v3/file_snippet/upload_revision.py b/drive/snippets/drive-v3/file_snippet/upload_revision.py
new file mode 100644
index 00000000..2fd6f3ff
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/upload_revision.py
@@ -0,0 +1,58 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_revision]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_revision(real_file_id):
+ """Replace the old file with new one on same file ID
+ Args: ID of the file to be replaced
+ Returns: file ID
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+ file_id = real_file_id
+ media = MediaFileUpload(
+ "download.jpeg", mimetype="image/jpeg", resumable=True
+ )
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .update(fileId=file_id, body={}, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: {file.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_revision(real_file_id="1jJTiihczk_xSNPVLwMySQBJACXYdpGTi")
+# [END drive_upload_revision]
diff --git a/drive/snippets/drive-v3/file_snippet/upload_to_folder.py b/drive/snippets/drive-v3/file_snippet/upload_to_folder.py
new file mode 100644
index 00000000..13441920
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/upload_to_folder.py
@@ -0,0 +1,59 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_to_folder]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_to_folder(folder_id):
+ """Upload a file to the specified folder and prints file ID, folder ID
+ Args: Id of the folder
+ Returns: ID of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_metadata = {"name": "photo.jpg", "parents": [folder_id]}
+ media = MediaFileUpload(
+ "download.jpeg", mimetype="image/jpeg", resumable=True
+ )
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .create(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File ID: "{file.get("id")}".')
+ return file.get("id")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return None
+
+
+if __name__ == "__main__":
+ upload_to_folder(folder_id="1s0oKEZZXjImNngxHGnY0xed6Mw-tvspu")
+# [END drive_upload_to_folder]
diff --git a/drive/snippets/drive-v3/file_snippet/upload_with_conversion.py b/drive/snippets/drive-v3/file_snippet/upload_with_conversion.py
new file mode 100644
index 00000000..cff3c070
--- /dev/null
+++ b/drive/snippets/drive-v3/file_snippet/upload_with_conversion.py
@@ -0,0 +1,60 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START drive_upload_with_conversion]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+from googleapiclient.http import MediaFileUpload
+
+
+def upload_with_conversion():
+ """Upload file with conversion
+ Returns: ID of the file uploaded
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ file_metadata = {
+ "name": "My Report",
+ "mimeType": "application/vnd.google-apps.spreadsheet",
+ }
+ media = MediaFileUpload("report.csv", mimetype="text/csv", resumable=True)
+ # pylint: disable=maybe-no-member
+ file = (
+ service.files()
+ .create(body=file_metadata, media_body=media, fields="id")
+ .execute()
+ )
+ print(f'File with ID: "{file.get("id")}" has been uploaded.')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ file = None
+
+ return file.get("id")
+
+
+if __name__ == "__main__":
+ upload_with_conversion()
+# [END drive_upload_with_conversion]
diff --git a/drive/snippets/drive-v3/team_drive_snippets/create_team_drive.py b/drive/snippets/drive-v3/team_drive_snippets/create_team_drive.py
new file mode 100644
index 00000000..cca27ce2
--- /dev/null
+++ b/drive/snippets/drive-v3/team_drive_snippets/create_team_drive.py
@@ -0,0 +1,57 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_create_team_drive]
+import uuid
+
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_team_drive():
+ """Create a drive for team.
+ Returns: ID of the created drive
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ team_drive_metadata = {"name": "Project Resources"}
+ request_id = str(uuid.uuid4())
+ team_drive = (
+ service.teamdrives()
+ .create(body=team_drive_metadata, requestId=request_id, fields="id")
+ .execute()
+ )
+ print(f'Team Drive ID: {team_drive.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ team_drive = None
+
+ return team_drive.get("id")
+
+
+if __name__ == "__main__":
+ create_team_drive()
+# [END drive_create_team_drive]
diff --git a/drive/snippets/drive-v3/team_drive_snippets/recover_team_drives.py b/drive/snippets/drive-v3/team_drive_snippets/recover_team_drives.py
new file mode 100644
index 00000000..3a082cbf
--- /dev/null
+++ b/drive/snippets/drive-v3/team_drive_snippets/recover_team_drives.py
@@ -0,0 +1,95 @@
+"""Copyright 2022 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.
+"""
+
+# [START drive_recover_team_drives]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def recover_team_drives(real_user):
+ """Finds all Team Drives without an organizer and add one
+ Args:
+ real_user:User ID for the new organizer.
+ Returns:
+ team drives_object.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # call drive api client
+ service = build("drive", "v3", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ team_drives = []
+
+ page_token = None
+ new_organizer_permission = {
+ "type": "user",
+ "role": "organizer",
+ "value": "user@example.com",
+ }
+
+ new_organizer_permission["emailAddress"] = real_user
+
+ while True:
+ response = (
+ service.teamdrives()
+ .list(
+ q="organizerCount = 0",
+ fields="nextPageToken, teamDrives(id, name)",
+ useDomainAdminAccess=True,
+ pageToken=page_token,
+ )
+ .execute()
+ )
+
+ for team_drive in response.get("teamDrives", []):
+ print(
+ "Found Team Drive without organizer: {team_drive.get("
+ '"title")},{team_drive.get("id")}'
+ )
+ permission = (
+ service.permissions()
+ .create(
+ fileId=team_drive.get("id"),
+ body=new_organizer_permission,
+ useDomainAdminAccess=True,
+ supportsTeamDrives=True,
+ fields="id",
+ )
+ .execute()
+ )
+ print(f'Added organizer permission:{permission.get("id")}')
+
+ team_drives.extend(response.get("teamDrives", []))
+ page_token = response.get("nextPageToken", None)
+ if page_token is None:
+ break
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ team_drives = None
+
+ print(team_drives)
+
+
+if __name__ == "__main__":
+ recover_team_drives(real_user="gduser1@workspacesamples.dev")
+# [END drive_recover_team_drives]
diff --git a/events/next18/customer_data_service.py b/events/next18/customer_data_service.py
index d7e2e143..84766454 100644
--- a/events/next18/customer_data_service.py
+++ b/events/next18/customer_data_service.py
@@ -22,106 +22,110 @@
class CustomerDataService(object):
- _CUSTOMER_DATA = {
- 'mars': {
- 'customer_name': 'Mars Inc.',
- 'customer_logo':
- 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/' +
- 'OSIRIS_Mars_true_color.jpg/550px-OSIRIS_Mars_true_color.jpg',
- 'curr_q': 'Q2',
- 'curr_q_total_sales': '$2,532,124',
- 'curr_q_qoq': '0.054',
- 'prev_q': 'Q1',
- 'prev_q_total_sales': '$2,413,584',
- 'next_q': 'Q3',
- 'next_q_total_sales_proj': '$2,634,765',
- 'next_q_qoq_proj': '0.041',
- 'top1_sku': 'Phobos',
- 'top1_sales': '$334,384',
- 'top2_sku': 'Deimos',
- 'top2_sales': '$315,718',
- 'top3_sku': 'Charon',
- 'top3_sales': '$285,727',
- 'top4_sku': 'Nix',
- 'top4_sales': '$264,023',
- 'top5_sku': 'Hydra',
- 'top5_sales': '$212,361',
- },
- 'jupiter': {
- 'customer_name': 'Jupiter LLC',
- 'customer_logo':
- 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/' +
- 'Jupiter_and_its_shrunken_Great_Red_Spot.jpg/660px-Jupiter_' +
- 'and_its_shrunken_Great_Red_Spot.jpg',
- 'curr_q': 'Q2',
- 'curr_q_total_sales': '$1,532,124',
- 'curr_q_qoq': '0.031',
- 'prev_q': 'Q1',
- 'prev_q_total_sales': '$1,413,584',
- 'next_q': 'Q3',
- 'next_q_total_sales_proj': '$1,634,765',
- 'next_q_qoq_proj': '0.021',
- 'top1_sku': 'Io',
- 'top1_sales': '$234,384',
- 'top2_sku': 'Europa',
- 'top2_sales': '$215,718',
- 'top3_sku': 'Ganymede',
- 'top3_sales': '$185,727',
- 'top4_sku': 'Callisto',
- 'top4_sales': '$164,023',
- 'top5_sku': 'Amalthea',
- 'top5_sales': '$112,361',
- },
- 'saturn': {
- 'customer_name': 'Saturn',
- 'customer_logo':
- 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/' +
- 'Saturn_during_Equinox.jpg/800px-Saturn_during_Equinox.jpg',
- 'curr_q': 'Q2',
- 'curr_q_total_sales': '$2,532,124',
- 'curr_q_qoq': '0.032',
- 'prev_q': 'Q1',
- 'prev_q_total_sales': '$2,413,584',
- 'next_q': 'Q3',
- 'next_q_total_sales_proj': '$2,634,765',
- 'next_q_qoq_proj': '0.029',
- 'top1_sku': 'Mimas',
- 'top1_sales': '$334,384',
- 'top2_sku': 'Enceladus',
- 'top2_sales': '$315,718',
- 'top3_sku': 'Tethys',
- 'top3_sales': '$285,727',
- 'top4_sku': 'Dione',
- 'top4_sales': '$264,023',
- 'top5_sku': 'Rhea',
- 'top5_sales': '$212,361',
- },
- 'neptune': {
- 'customer_name': 'Neptune',
- 'customer_logo':
- 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/' +
- 'Neptune_Full.jpg/600px-Neptune_Full.jpg',
- 'curr_q': 'Q2',
- 'curr_q_total_sales': '$2,532,124',
- 'curr_q_qoq': '0.027',
- 'prev_q': 'Q1',
- 'prev_q_total_sales': '$2,413,584',
- 'next_q': 'Q3',
- 'next_q_total_sales_proj': '$2,634,765',
- 'next_q_qoq_proj': '0.039',
- 'top1_sku': 'Triton',
- 'top1_sales': '$334,384',
- 'top2_sku': 'Nereid',
- 'top2_sales': '$315,718',
- 'top3_sku': 'Naiad',
- 'top3_sales': '$285,727',
- 'top4_sku': 'Thalassa',
- 'top4_sales': '$264,023',
- 'top5_sku': 'Despina',
- 'top5_sales': '$212,361',
- },
- }
+ _CUSTOMER_DATA = {
+ "mars": {
+ "customer_name": "Mars Inc.",
+ "customer_logo": (
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/"
+ + "OSIRIS_Mars_true_color.jpg/550px-OSIRIS_Mars_true_color.jpg"
+ ),
+ "curr_q": "Q2",
+ "curr_q_total_sales": "$2,532,124",
+ "curr_q_qoq": "0.054",
+ "prev_q": "Q1",
+ "prev_q_total_sales": "$2,413,584",
+ "next_q": "Q3",
+ "next_q_total_sales_proj": "$2,634,765",
+ "next_q_qoq_proj": "0.041",
+ "top1_sku": "Phobos",
+ "top1_sales": "$334,384",
+ "top2_sku": "Deimos",
+ "top2_sales": "$315,718",
+ "top3_sku": "Charon",
+ "top3_sales": "$285,727",
+ "top4_sku": "Nix",
+ "top4_sales": "$264,023",
+ "top5_sku": "Hydra",
+ "top5_sales": "$212,361",
+ },
+ "jupiter": {
+ "customer_name": "Jupiter LLC",
+ "customer_logo": (
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/"
+ + "Jupiter_and_its_shrunken_Great_Red_Spot.jpg/660px-Jupiter_"
+ + "and_its_shrunken_Great_Red_Spot.jpg"
+ ),
+ "curr_q": "Q2",
+ "curr_q_total_sales": "$1,532,124",
+ "curr_q_qoq": "0.031",
+ "prev_q": "Q1",
+ "prev_q_total_sales": "$1,413,584",
+ "next_q": "Q3",
+ "next_q_total_sales_proj": "$1,634,765",
+ "next_q_qoq_proj": "0.021",
+ "top1_sku": "Io",
+ "top1_sales": "$234,384",
+ "top2_sku": "Europa",
+ "top2_sales": "$215,718",
+ "top3_sku": "Ganymede",
+ "top3_sales": "$185,727",
+ "top4_sku": "Callisto",
+ "top4_sales": "$164,023",
+ "top5_sku": "Amalthea",
+ "top5_sales": "$112,361",
+ },
+ "saturn": {
+ "customer_name": "Saturn",
+ "customer_logo": (
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/"
+ + "Saturn_during_Equinox.jpg/800px-Saturn_during_Equinox.jpg"
+ ),
+ "curr_q": "Q2",
+ "curr_q_total_sales": "$2,532,124",
+ "curr_q_qoq": "0.032",
+ "prev_q": "Q1",
+ "prev_q_total_sales": "$2,413,584",
+ "next_q": "Q3",
+ "next_q_total_sales_proj": "$2,634,765",
+ "next_q_qoq_proj": "0.029",
+ "top1_sku": "Mimas",
+ "top1_sales": "$334,384",
+ "top2_sku": "Enceladus",
+ "top2_sales": "$315,718",
+ "top3_sku": "Tethys",
+ "top3_sales": "$285,727",
+ "top4_sku": "Dione",
+ "top4_sales": "$264,023",
+ "top5_sku": "Rhea",
+ "top5_sales": "$212,361",
+ },
+ "neptune": {
+ "customer_name": "Neptune",
+ "customer_logo": (
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/"
+ + "Neptune_Full.jpg/600px-Neptune_Full.jpg"
+ ),
+ "curr_q": "Q2",
+ "curr_q_total_sales": "$2,532,124",
+ "curr_q_qoq": "0.027",
+ "prev_q": "Q1",
+ "prev_q_total_sales": "$2,413,584",
+ "next_q": "Q3",
+ "next_q_total_sales_proj": "$2,634,765",
+ "next_q_qoq_proj": "0.039",
+ "top1_sku": "Triton",
+ "top1_sales": "$334,384",
+ "top2_sku": "Nereid",
+ "top2_sales": "$315,718",
+ "top3_sku": "Naiad",
+ "top3_sales": "$285,727",
+ "top4_sku": "Thalassa",
+ "top4_sales": "$264,023",
+ "top5_sku": "Despina",
+ "top5_sales": "$212,361",
+ },
+ }
- def GetCustomerData(self, customer_id, properties):
- customer_data = self._CUSTOMER_DATA[customer_id]
- return [customer_data[p.lower()] for p in properties]
+ def GetCustomerData(self, customer_id, properties):
+ customer_data = self._CUSTOMER_DATA[customer_id]
+ return [customer_data[p.lower()] for p in properties]
diff --git a/events/next18/customer_spreadsheet_reader.py b/events/next18/customer_spreadsheet_reader.py
index e0c6167d..28008c89 100644
--- a/events/next18/customer_spreadsheet_reader.py
+++ b/events/next18/customer_spreadsheet_reader.py
@@ -21,54 +21,62 @@
class CustomerSpreadsheetReader(object):
- def __init__(self, sheets_service, spreadsheet_id):
- self._sheets_service = sheets_service
- self._spreadsheet_id = spreadsheet_id
- self._data_filters = collections.OrderedDict()
+ def __init__(self, sheets_service, spreadsheet_id):
+ self._sheets_service = sheets_service
+ self._spreadsheet_id = spreadsheet_id
+ self._data_filters = collections.OrderedDict()
- def ReadColumnData(self, column_id):
- data_filter = {
- 'developerMetadataLookup': {
- 'metadataKey': 'column_id',
- 'metadataValue': column_id,
- }
+ def ReadColumnData(self, column_id):
+ data_filter = {
+ "developerMetadataLookup": {
+ "metadataKey": "column_id",
+ "metadataValue": column_id,
}
- self._data_filters[column_id] = data_filter
+ }
+ self._data_filters[column_id] = data_filter
- def ExecuteRead(self):
- filters = list(self._data_filters.values())
- get_body = {'dataFilters': filters}
- read_fields = ','.join([
- 'sheets.properties.sheetId',
- 'sheets.data.rowData.values.formattedValue',
- 'developerMetadata.metadataValue'])
- spreadsheet = self._sheets_service.spreadsheets().getByDataFilter(
- spreadsheetId=self._spreadsheet_id, body=get_body,
- fields=read_fields).execute()
- customer_spreadsheet = CustomerSpreadsheet(
- spreadsheet, self._data_filters)
- self._data_filters = collections.OrderedDict()
- return customer_spreadsheet
+ def ExecuteRead(self):
+ filters = list(self._data_filters.values())
+ get_body = {"dataFilters": filters}
+ read_fields = ",".join([
+ "sheets.properties.sheetId",
+ "sheets.data.rowData.values.formattedValue",
+ "developerMetadata.metadataValue",
+ ])
+ spreadsheet = (
+ self._sheets_service.spreadsheets()
+ .getByDataFilter(
+ spreadsheetId=self._spreadsheet_id,
+ body=get_body,
+ fields=read_fields,
+ )
+ .execute()
+ )
+ customer_spreadsheet = CustomerSpreadsheet(spreadsheet, self._data_filters)
+ self._data_filters = collections.OrderedDict()
+ return customer_spreadsheet
class CustomerSpreadsheet(object):
- def __init__(self, spreadsheet, data_filters):
- self._spreadsheet = spreadsheet
- self._data_filters = data_filters
+ def __init__(self, spreadsheet, data_filters):
+ self._spreadsheet = spreadsheet
+ self._data_filters = data_filters
- def GetSheetId(self):
- sheet = self._spreadsheet.get('sheets')[0]
- return sheet.get('properties').get('sheetId')
+ def GetSheetId(self):
+ sheet = self._spreadsheet.get("sheets")[0]
+ return sheet.get("properties").get("sheetId")
- def GetTemplateId(self):
- metadata = self._spreadsheet.get('developerMetadata')[0]
- return metadata.get('metadataValue')
+ def GetTemplateId(self):
+ metadata = self._spreadsheet.get("developerMetadata")[0]
+ return metadata.get("metadataValue")
- def GetColumnData(self, column_id):
- index = list(self._data_filters.keys()).index(column_id)
- data = self._spreadsheet.get('sheets')[0].get('data')[index]
- values = [row.get('values')[0].get('formattedValue')
- for row in data.get('rowData')]
- # Remove the first value which is just the label
- return values[1:]
+ def GetColumnData(self, column_id):
+ index = list(self._data_filters.keys()).index(column_id)
+ data = self._spreadsheet.get("sheets")[0].get("data")[index]
+ values = [
+ row.get("values")[0].get("formattedValue")
+ for row in data.get("rowData")
+ ]
+ # Remove the first value which is just the label
+ return values[1:]
diff --git a/events/next18/presentation_reader.py b/events/next18/presentation_reader.py
index edc82861..4b023b50 100644
--- a/events/next18/presentation_reader.py
+++ b/events/next18/presentation_reader.py
@@ -24,54 +24,55 @@
class PresentationReader(object):
- def __init__(self, slides_service, presentation_id):
- self._slides_service = slides_service
- self._presentation_id = presentation_id
- self._presentation = None
+ def __init__(self, slides_service, presentation_id):
+ self._slides_service = slides_service
+ self._presentation_id = presentation_id
+ self._presentation = None
- def _InitPresentation(self):
- if not self._presentation:
- self._presentation = self._slides_service.presentations().get(
- presentationId=self._presentation_id).execute()
+ def _InitPresentation(self):
+ if not self._presentation:
+ self._presentation = (
+ self._slides_service.presentations()
+ .get(presentationId=self._presentation_id)
+ .execute()
+ )
- def GetTitle(self):
- self._InitPresentation()
- return self._presentation.get('title')
+ def GetTitle(self):
+ self._InitPresentation()
+ return self._presentation.get("title")
- def GetAllPlaceholders(self):
- self._InitPresentation()
- slides = self._presentation.get('slides')
- placeholders = []
- for slide in slides:
- elements = slide.get('pageElements')
- for element in elements:
- shape = element.get('shape')
- table = element.get('table')
- # Skip page elements that aren't shapes or tables since they're
- # the only types that support text.
- if not shape and not table:
- continue
- if shape:
- placeholders += self._GetPlaceholdersFromText(
- shape.get('text'))
- elif table:
- rows = table.get('tableRows')
- for row in rows:
- cells = row.get('tableCells')
- for cell in cells:
- placeholders += self._GetPlaceholdersFromText(
- cell.get('text'))
- # Return the unique placeholders
- seen = set()
- return [p for p in placeholders if not (p in seen or seen.add(p))]
+ def GetAllPlaceholders(self):
+ self._InitPresentation()
+ slides = self._presentation.get("slides")
+ placeholders = []
+ for slide in slides:
+ elements = slide.get("pageElements")
+ for element in elements:
+ shape = element.get("shape")
+ table = element.get("table")
+ # Skip page elements that aren't shapes or tables since they're
+ # the only types that support text.
+ if not shape and not table:
+ continue
+ if shape:
+ placeholders += self._GetPlaceholdersFromText(shape.get("text"))
+ elif table:
+ rows = table.get("tableRows")
+ for row in rows:
+ cells = row.get("tableCells")
+ for cell in cells:
+ placeholders += self._GetPlaceholdersFromText(cell.get("text"))
+ # Return the unique placeholders
+ seen = set()
+ return [p for p in placeholders if not (p in seen or seen.add(p))]
- def _GetPlaceholdersFromText(self, text):
- if not text:
- return []
- placeholders = []
- elements = text.get('textElements')
- for element in elements:
- if element.get('textRun'):
- content = element.get('textRun').get('content')
- placeholders += re.findall('{.*?}', content)
- return placeholders
+ def _GetPlaceholdersFromText(self, text):
+ if not text:
+ return []
+ placeholders = []
+ elements = text.get("textElements")
+ for element in elements:
+ if element.get("textRun"):
+ content = element.get("textRun").get("content")
+ placeholders += re.findall("{.*?}", content)
+ return placeholders
diff --git a/events/next18/presentation_writer.py b/events/next18/presentation_writer.py
index 16cfb568..7436ec89 100644
--- a/events/next18/presentation_writer.py
+++ b/events/next18/presentation_writer.py
@@ -14,47 +14,41 @@
# pylint: disable=E1102
# python3
-"""Functionality for writing to a presentation.
-"""
+"""Functionality for writing to a presentation."""
class PresentationWriter(object):
- """Queues writes for modifying a presentation.
-
- Call ExecuteBatchUpdate to flush pending writes.
- """
-
- def __init__(self, slides_service, presentation_id):
- self._slides_service = slides_service
- self._presentation_id = presentation_id
- self._requests = []
-
- def ReplaceAllText(self, find_text, replace_text):
- request = {
- 'replaceAllText': {
- 'replaceText': replace_text,
- 'containsText': {
- 'text': find_text,
- 'matchCase': True
- }
- }
+ """Queues writes for modifying a presentation.
+
+ Call ExecuteBatchUpdate to flush pending writes.
+ """
+
+ def __init__(self, slides_service, presentation_id):
+ self._slides_service = slides_service
+ self._presentation_id = presentation_id
+ self._requests = []
+
+ def ReplaceAllText(self, find_text, replace_text):
+ request = {
+ "replaceAllText": {
+ "replaceText": replace_text,
+ "containsText": {"text": find_text, "matchCase": True},
}
- self._requests.append(request)
-
- def ReplaceAllShapesWithImage(self, find_text, image_url):
- request = {
- 'replaceAllShapesWithImage': {
- 'imageUrl': image_url,
- 'containsText': {
- 'text': find_text,
- 'matchCase': True
- }
- }
+ }
+ self._requests.append(request)
+
+ def ReplaceAllShapesWithImage(self, find_text, image_url):
+ request = {
+ "replaceAllShapesWithImage": {
+ "imageUrl": image_url,
+ "containsText": {"text": find_text, "matchCase": True},
}
- self._requests.append(request)
-
- def ExecuteBatchUpdate(self):
- body = {'requests': self._requests}
- self._requests = []
- self._slides_service.presentations().batchUpdate(
- presentationId=self._presentation_id, body=body).execute()
+ }
+ self._requests.append(request)
+
+ def ExecuteBatchUpdate(self):
+ body = {"requests": self._requests}
+ self._requests = []
+ self._slides_service.presentations().batchUpdate(
+ presentationId=self._presentation_id, body=body
+ ).execute()
diff --git a/events/next18/qbr_tool.py b/events/next18/qbr_tool.py
index cf1e49e8..15a06fa3 100644
--- a/events/next18/qbr_tool.py
+++ b/events/next18/qbr_tool.py
@@ -20,8 +20,6 @@
pushes the data to Google Slides
"""
-from __future__ import print_function
-
import argparse
import re
@@ -36,149 +34,163 @@
from oauth2client import file as oauth_file
from oauth2client import tools
-SCOPES = ['https://www.googleapis.com/auth/drive']
-store = oauth_file.Storage('token.json')
+SCOPES = ["https://www.googleapis.com/auth/drive"]
+store = oauth_file.Storage("token.json")
creds = store.get()
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("credentials.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-slides_service = build('slides', 'v1', http=creds.authorize(Http()))
-sheets_service = build('sheets', 'v4', http=creds.authorize(Http()))
-drive_service = build('drive', 'v3', http=creds.authorize(Http()))
+slides_service = build("slides", "v1", http=creds.authorize(Http()))
+sheets_service = build("sheets", "v4", http=creds.authorize(Http()))
+drive_service = build("drive", "v3", http=creds.authorize(Http()))
def main():
- parser = argparse.ArgumentParser()
- parser.add_argument(
- 'command',
- help='The command to run',
- choices=['create_sheet', 'create_presentations', 'add_customers'])
- parser.add_argument('--spreadsheet_id', help='The spreadsheet to use')
- parser.add_argument(
- '--template_id', help='The presentation to use as a template')
- parser.add_argument(
- '--customer_ids', nargs='+', help='The customers to use')
- args = parser.parse_args()
-
- if args.command == 'create_sheet':
- create_sheet(args.template_id)
- elif args.command == 'create_presentations':
- create_presentations(args.spreadsheet_id, args.customer_ids)
- elif args.command == 'add_customers':
- add_customers(args.spreadsheet_id, args.customer_ids)
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "command",
+ help="The command to run",
+ choices=["create_sheet", "create_presentations", "add_customers"],
+ )
+ parser.add_argument("--spreadsheet_id", help="The spreadsheet to use")
+ parser.add_argument(
+ "--template_id", help="The presentation to use as a template"
+ )
+ parser.add_argument("--customer_ids", nargs="+", help="The customers to use")
+ args = parser.parse_args()
+
+ if args.command == "create_sheet":
+ create_sheet(args.template_id)
+ elif args.command == "create_presentations":
+ create_presentations(args.spreadsheet_id, args.customer_ids)
+ elif args.command == "add_customers":
+ add_customers(args.spreadsheet_id, args.customer_ids)
def create_sheet(template_id):
- pres_reader = presentation_reader.PresentationReader(
- slides_service, template_id)
- placeholders = pres_reader.GetAllPlaceholders()
- presentation_title = pres_reader.GetTitle()
-
- # Create the data manager spreadsheet
- spreadsheet_title = 'Data Sheet - ' + presentation_title
- spreadsheet = spreadsheet_writer.CreateSpreadsheet(
- sheets_service=sheets_service,
- title=spreadsheet_title,
- sheet_titles=['Customer Data'])
-
- # Get the spreadsheet ID and sheet IDs from the created spreadsheet.
- spreadsheet_id = spreadsheet.get('spreadsheetId')
- sheet_id = spreadsheet.get('sheets')[0].get('properties').get('sheetId')
-
- # Write the placeholders and metadata to the spreadsheet.
- writer = spreadsheet_writer.SpreadsheetWriter(
- sheets_service, spreadsheet_id)
- writer.PopulateColumn(
- sheet_id=sheet_id,
- column_index=0,
- column_id='placeholders',
- values=placeholders)
- writer.AddTemplateIdToSpreadsheetMetadata(template_id)
- writer.ExecuteBatchUpdate()
-
- print('Spreadsheet URL: https://docs.google.com/spreadsheets/d/' +
- spreadsheet_id)
+ pres_reader = presentation_reader.PresentationReader(
+ slides_service, template_id
+ )
+ placeholders = pres_reader.GetAllPlaceholders()
+ presentation_title = pres_reader.GetTitle()
+
+ # Create the data manager spreadsheet
+ spreadsheet_title = "Data Sheet - " + presentation_title
+ spreadsheet = spreadsheet_writer.CreateSpreadsheet(
+ sheets_service=sheets_service,
+ title=spreadsheet_title,
+ sheet_titles=["Customer Data"],
+ )
+
+ # Get the spreadsheet ID and sheet IDs from the created spreadsheet.
+ spreadsheet_id = spreadsheet.get("spreadsheetId")
+ sheet_id = spreadsheet.get("sheets")[0].get("properties").get("sheetId")
+
+ # Write the placeholders and metadata to the spreadsheet.
+ writer = spreadsheet_writer.SpreadsheetWriter(sheets_service, spreadsheet_id)
+ writer.PopulateColumn(
+ sheet_id=sheet_id,
+ column_index=0,
+ column_id="placeholders",
+ values=placeholders,
+ )
+ writer.AddTemplateIdToSpreadsheetMetadata(template_id)
+ writer.ExecuteBatchUpdate()
+
+ print(
+ "Spreadsheet URL: https://docs.google.com/spreadsheets/d/"
+ + spreadsheet_id
+ )
def add_customers(spreadsheet_id, customer_ids):
- # Read the placeholders by querying for the developer metadata we added
- # while creating the spreadsheet
- spreadsheet_reader = customer_spreadsheet_reader.CustomerSpreadsheetReader(
- sheets_service, spreadsheet_id)
- spreadsheet_reader.ReadColumnData('placeholders')
- customer_spreadsheet = spreadsheet_reader.ExecuteRead()
-
- sheet_id = customer_spreadsheet.GetSheetId()
- placeholders = customer_spreadsheet.GetColumnData('placeholders')
-
- # Process the placeholders into our query properties
- properties = []
- for p in placeholders:
- # Remove any suffix from the property name
- m = re.search(r'{(\w+)(\.\w+)*}', p)
- properties.append(m.group(1))
-
- data_service = customer_data_service.CustomerDataService()
- writer = spreadsheet_writer.SpreadsheetWriter(
- sheets_service, spreadsheet_id)
-
- for customer_id in customer_ids:
- # Get the customer data from the internal customer data service
- customer_data = data_service.GetCustomerData(customer_id, properties)
-
- # Write the customer data to the spreadsheet
- writer.InsertColumn(sheet_id=sheet_id, column_index=1)
- writer.PopulateColumn(
- sheet_id=sheet_id,
- column_index=1,
- column_id=customer_id,
- values=customer_data)
-
- writer.ExecuteBatchUpdate()
+ # Read the placeholders by querying for the developer metadata we added
+ # while creating the spreadsheet
+ spreadsheet_reader = customer_spreadsheet_reader.CustomerSpreadsheetReader(
+ sheets_service, spreadsheet_id
+ )
+ spreadsheet_reader.ReadColumnData("placeholders")
+ customer_spreadsheet = spreadsheet_reader.ExecuteRead()
+
+ sheet_id = customer_spreadsheet.GetSheetId()
+ placeholders = customer_spreadsheet.GetColumnData("placeholders")
+
+ # Process the placeholders into our query properties
+ properties = []
+ for p in placeholders:
+ # Remove any suffix from the property name
+ m = re.search(r"{(\w+)(\.\w+)*}", p)
+ properties.append(m.group(1))
+
+ data_service = customer_data_service.CustomerDataService()
+ writer = spreadsheet_writer.SpreadsheetWriter(sheets_service, spreadsheet_id)
+
+ for customer_id in customer_ids:
+ # Get the customer data from the internal customer data service
+ customer_data = data_service.GetCustomerData(customer_id, properties)
+
+ # Write the customer data to the spreadsheet
+ writer.InsertColumn(sheet_id=sheet_id, column_index=1)
+ writer.PopulateColumn(
+ sheet_id=sheet_id,
+ column_index=1,
+ column_id=customer_id,
+ values=customer_data,
+ )
+
+ writer.ExecuteBatchUpdate()
def create_presentations(spreadsheet_id, customer_ids):
- spreadsheet_reader = customer_spreadsheet_reader.CustomerSpreadsheetReader(
- sheets_service, spreadsheet_id)
-
- spreadsheet_reader.ReadColumnData('placeholders')
- for customer_id in customer_ids:
- spreadsheet_reader.ReadColumnData(customer_id)
-
- customer_spreadsheet = spreadsheet_reader.ExecuteRead()
- placeholders = customer_spreadsheet.GetColumnData('placeholders')
-
- # Get the template presentation ID and its title
- template_id = customer_spreadsheet.GetTemplateId()
- pres_reader = presentation_reader.PresentationReader(
- slides_service, template_id)
- title = pres_reader.GetTitle()
-
- # Generate a presentation for each customer
- for customer_id in customer_ids:
- # Create a copy of the presentation
- new_title = customer_id + ' - ' + title
- presentation_id = drive_service.files().copy(
- fileId=template_id, body={
- 'name': new_title
- }).execute().get('id')
-
- # Replace the placeholders with the customer data in the copy
- data = customer_spreadsheet.GetColumnData(customer_id)
- data_dict = dict(zip(placeholders, data))
- writer = presentation_writer.PresentationWriter(slides_service,
- presentation_id)
- for placeholder, value in data_dict.items():
- if re.findall(r'{(\w+).image}', placeholder):
- writer.ReplaceAllShapesWithImage(placeholder, value)
- else:
- writer.ReplaceAllText(placeholder, value)
- writer.ExecuteBatchUpdate()
-
- print(customer_id +
- ': https://docs.google.com/presentation/d/' + presentation_id)
-
-
-if __name__ == '__main__':
- main()
+ spreadsheet_reader = customer_spreadsheet_reader.CustomerSpreadsheetReader(
+ sheets_service, spreadsheet_id
+ )
+
+ spreadsheet_reader.ReadColumnData("placeholders")
+ for customer_id in customer_ids:
+ spreadsheet_reader.ReadColumnData(customer_id)
+
+ customer_spreadsheet = spreadsheet_reader.ExecuteRead()
+ placeholders = customer_spreadsheet.GetColumnData("placeholders")
+
+ # Get the template presentation ID and its title
+ template_id = customer_spreadsheet.GetTemplateId()
+ pres_reader = presentation_reader.PresentationReader(
+ slides_service, template_id
+ )
+ title = pres_reader.GetTitle()
+
+ # Generate a presentation for each customer
+ for customer_id in customer_ids:
+ # Create a copy of the presentation
+ new_title = customer_id + " - " + title
+ presentation_id = (
+ drive_service.files()
+ .copy(fileId=template_id, body={"name": new_title})
+ .execute()
+ .get("id")
+ )
+
+ # Replace the placeholders with the customer data in the copy
+ data = customer_spreadsheet.GetColumnData(customer_id)
+ data_dict = dict(zip(placeholders, data))
+ writer = presentation_writer.PresentationWriter(
+ slides_service, presentation_id
+ )
+ for placeholder, value in data_dict.items():
+ if re.findall(r"{(\w+).image}", placeholder):
+ writer.ReplaceAllShapesWithImage(placeholder, value)
+ else:
+ writer.ReplaceAllText(placeholder, value)
+ writer.ExecuteBatchUpdate()
+
+ print(
+ customer_id
+ + ": https://docs.google.com/presentation/d/"
+ + presentation_id
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/events/next18/spreadsheet_writer.py b/events/next18/spreadsheet_writer.py
index 4e7e880b..7f285ad3 100644
--- a/events/next18/spreadsheet_writer.py
+++ b/events/next18/spreadsheet_writer.py
@@ -18,122 +18,115 @@
def CreateSpreadsheet(sheets_service, title, sheet_titles):
- """Creates an empty spreadsheet.
-
- It creates a spreadsheet with the provided title, and creates a sheet for
- each entry in the sheet_titles list with the corresponding sheet title.
- """
- sheets = []
- for sheet_title in sheet_titles:
- sheet = {
- 'properties': {
- 'title': sheet_title,
- },
- }
- sheets.append(sheet)
-
- spreadsheet = {
- 'properties': {
- 'title': title,
+ """Creates an empty spreadsheet.
+
+ It creates a spreadsheet with the provided title, and creates a sheet for
+ each entry in the sheet_titles list with the corresponding sheet title.
+ """
+ sheets = []
+ for sheet_title in sheet_titles:
+ sheet = {
+ "properties": {
+ "title": sheet_title,
},
- 'sheets': sheets,
}
- return sheets_service.spreadsheets().create(body=spreadsheet).execute()
+ sheets.append(sheet)
+
+ spreadsheet = {
+ "properties": {
+ "title": title,
+ },
+ "sheets": sheets,
+ }
+ return sheets_service.spreadsheets().create(body=spreadsheet).execute()
class SpreadsheetWriter(object):
- """Queues writes for modifying a spreadsheet.
-
- Call ExecuteBatchUpdate to flush pending writes.
- """
-
- def __init__(self, sheets_service, spreadsheet_id):
- self._sheets_service = sheets_service
- self._spreadsheet_id = spreadsheet_id
- self._requests = []
-
- def InsertColumn(self, sheet_id, column_index):
- request = {
- 'insertDimension': {
- 'range': {
- 'sheetId': sheet_id,
- 'dimension': 'COLUMNS',
- 'startIndex': column_index,
- 'endIndex': column_index + 1,
- },
- }
+ """Queues writes for modifying a spreadsheet.
+
+ Call ExecuteBatchUpdate to flush pending writes.
+ """
+
+ def __init__(self, sheets_service, spreadsheet_id):
+ self._sheets_service = sheets_service
+ self._spreadsheet_id = spreadsheet_id
+ self._requests = []
+
+ def InsertColumn(self, sheet_id, column_index):
+ request = {
+ "insertDimension": {
+ "range": {
+ "sheetId": sheet_id,
+ "dimension": "COLUMNS",
+ "startIndex": column_index,
+ "endIndex": column_index + 1,
+ },
}
- self._requests.append(request)
-
- def PopulateColumn(self, sheet_id, column_index, column_id, values):
- # Include the column ID in the column values
- values = [column_id] + values
-
- # Populate the column with the values
- rows = []
- for value in values:
- row_data = {
- 'values': [
- {
- 'userEnteredValue': {
- 'stringValue': value
- }
- }
- ]
- }
- rows.append(row_data)
-
- update_request = {
- 'updateCells': {
- 'rows': rows,
- 'fields': 'userEnteredValue',
- 'start': {
- 'sheetId': sheet_id,
- 'rowIndex': 0,
- 'columnIndex': column_index
- }
- }
+ }
+ self._requests.append(request)
+
+ def PopulateColumn(self, sheet_id, column_index, column_id, values):
+ # Include the column ID in the column values
+ values = [column_id] + values
+
+ # Populate the column with the values
+ rows = []
+ for value in values:
+ row_data = {"values": [{"userEnteredValue": {"stringValue": value}}]}
+ rows.append(row_data)
+
+ update_request = {
+ "updateCells": {
+ "rows": rows,
+ "fields": "userEnteredValue",
+ "start": {
+ "sheetId": sheet_id,
+ "rowIndex": 0,
+ "columnIndex": column_index,
+ },
}
- self._requests.append(update_request)
-
- # Add developer metadata to the column to make it easier to read later
- # by being able to just query it by the column ID
- metadata_request = {
- 'createDeveloperMetadata': {
- 'developerMetadata': {
- 'metadataKey': 'column_id',
- 'metadataValue': column_id,
- 'location': {
- 'dimensionRange': {
- 'sheetId': sheet_id,
- 'dimension': 'COLUMNS',
- 'startIndex': column_index,
- 'endIndex': column_index + 1,
- }
- },
- 'visibility': 'DOCUMENT',
- }
+ }
+ self._requests.append(update_request)
+
+ # Add developer metadata to the column to make it easier to read later
+ # by being able to just query it by the column ID
+ metadata_request = {
+ "createDeveloperMetadata": {
+ "developerMetadata": {
+ "metadataKey": "column_id",
+ "metadataValue": column_id,
+ "location": {
+ "dimensionRange": {
+ "sheetId": sheet_id,
+ "dimension": "COLUMNS",
+ "startIndex": column_index,
+ "endIndex": column_index + 1,
+ }
+ },
+ "visibility": "DOCUMENT",
}
}
- self._requests.append(metadata_request)
-
- def AddTemplateIdToSpreadsheetMetadata(self, template_id):
- request = {
- 'createDeveloperMetadata': {
- 'developerMetadata': {
- 'metadataKey': 'template_id',
- 'metadataValue': template_id,
- 'location': {
- 'spreadsheet': True
- },
- 'visibility': 'DOCUMENT',
- }
+ }
+ self._requests.append(metadata_request)
+
+ def AddTemplateIdToSpreadsheetMetadata(self, template_id):
+ request = {
+ "createDeveloperMetadata": {
+ "developerMetadata": {
+ "metadataKey": "template_id",
+ "metadataValue": template_id,
+ "location": {"spreadsheet": True},
+ "visibility": "DOCUMENT",
}
}
- self._requests.append(request)
-
- def ExecuteBatchUpdate(self):
- body = {'requests': self._requests}
- self._requests = []
- return self._sheets_service.spreadsheets().batchUpdate(
- spreadsheetId=self._spreadsheet_id, body=body).execute()
+ }
+ self._requests.append(request)
+
+ def ExecuteBatchUpdate(self):
+ body = {"requests": self._requests}
+ self._requests = []
+ return (
+ self._sheets_service.spreadsheets()
+ .batchUpdate(spreadsheetId=self._spreadsheet_id, body=body)
+ .execute()
+ )
diff --git a/forms/quickstart/README.md b/forms/quickstart/README.md
new file mode 100644
index 00000000..bbcb3bdd
--- /dev/null
+++ b/forms/quickstart/README.md
@@ -0,0 +1,18 @@
+# Google Forms Python Quickstart
+
+Complete the steps described in the [Google Forms Python Quickstart](
+https://developers.google.com/forms/quickstart/python), and in
+about five minutes you'll have a simple Python command-line application that
+makes requests to the Google Forms API.
+
+## Install
+
+```shell
+pip install -r requirements.txt
+```
+
+## Run
+
+```shell
+python quickstart.py
+```
diff --git a/forms/quickstart/quickstart.py b/forms/quickstart/quickstart.py
new file mode 100644
index 00000000..7291e14a
--- /dev/null
+++ b/forms/quickstart/quickstart.py
@@ -0,0 +1,90 @@
+# 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.
+
+# [START forms_quickstart]
+from apiclient import discovery
+from httplib2 import Http
+from oauth2client import client, file, tools
+
+SCOPES = "https://www.googleapis.com/auth/forms.body"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
+
+store = file.Storage("token.json")
+creds = None
+if not creds or creds.invalid:
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+
+form_service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
+
+# Request body for creating a form
+NEW_FORM = {
+ "info": {
+ "title": "Quickstart form",
+ }
+}
+
+# Request body to add a multiple-choice question
+NEW_QUESTION = {
+ "requests": [
+ {
+ "createItem": {
+ "item": {
+ "title": (
+ "In what year did the United States land a mission on"
+ " the moon?"
+ ),
+ "questionItem": {
+ "question": {
+ "required": True,
+ "choiceQuestion": {
+ "type": "RADIO",
+ "options": [
+ {"value": "1965"},
+ {"value": "1967"},
+ {"value": "1969"},
+ {"value": "1971"},
+ ],
+ "shuffle": True,
+ },
+ }
+ },
+ },
+ "location": {"index": 0},
+ }
+ }
+ ]
+}
+
+# Creates the initial form
+result = form_service.forms().create(body=NEW_FORM).execute()
+
+# Adds the question to the form
+question_setting = (
+ form_service.forms()
+ .batchUpdate(formId=result["formId"], body=NEW_QUESTION)
+ .execute()
+)
+
+# Prints the result to show the question has been added
+get_result = form_service.forms().get(formId=result["formId"]).execute()
+print(get_result)
+
+# [END forms_quickstart]
diff --git a/drive/activity/requirements.txt b/forms/quickstart/requirements.txt
similarity index 100%
rename from drive/activity/requirements.txt
rename to forms/quickstart/requirements.txt
diff --git a/forms/snippets/README.md b/forms/snippets/README.md
deleted file mode 100644
index bf5f8862..00000000
--- a/forms/snippets/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Google Forms API
-
-The Google Forms API is currently in Restricted Beta. To use the API and these samples prior to General Availability,
-your Google Cloud project must be allowlisted. To request that your project be allowlisted, complete the
-[Early Adopter Program application](https://developers.google.com/forms/api/eap).
diff --git a/forms/snippets/add_item.py b/forms/snippets/add_item.py
index b2a9f242..b7e24671 100644
--- a/forms/snippets/add_item.py
+++ b/forms/snippets/add_item.py
@@ -13,24 +13,26 @@
# limitations under the License.
# [START forms_add_item]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.body"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-form_service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+form_service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
form = {
"info": {
@@ -43,28 +45,32 @@
# Request body to add a video item to a Form
update = {
- "requests": [{
- "createItem": {
- "item": {
- "title": "Homework video",
- "description": "Quizzes in Google Forms",
- "videoItem": {
- "video": {
- "youtubeUri": "https://www.youtube.com/watch?v=Lt5HqPvM-eI"
- }
- }
- },
- "location": {
- "index": 0
+ "requests": [
+ {
+ "createItem": {
+ "item": {
+ "title": "Homework video",
+ "description": "Quizzes in Google Forms",
+ "videoItem": {
+ "video": {
+ "youtubeUri": (
+ "https://www.youtube.com/watch?v=Lt5HqPvM-eI"
+ )
+ }
+ },
+ },
+ "location": {"index": 0},
}
}
- }
]
}
# Add the video to the form
-question_setting = form_service.forms().batchUpdate(
- formId=createResult["formId"], body=update).execute()
+question_setting = (
+ form_service.forms()
+ .batchUpdate(formId=createResult["formId"], body=update)
+ .execute()
+)
# Print the result to see it now has a video
result = form_service.forms().get(formId=createResult["formId"]).execute()
diff --git a/forms/snippets/add_responder.py b/forms/snippets/add_responder.py
new file mode 100644
index 00000000..7a6d367d
--- /dev/null
+++ b/forms/snippets/add_responder.py
@@ -0,0 +1,86 @@
+# Copyright 2025 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.
+
+# [START forms_add_responder]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/drive.file"]
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID and responder's email
+YOUR_FORM_ID = "YOUR_FORM_ID"
+YOUR_RESPONDER_EMAIL = "user@example.com"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def add_responder():
+ """Adds the responder to the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+
+ permission_body = {
+ "view": "published",
+ "role": "reader",
+ "type": "user",
+ "emailAddress": YOUR_RESPONDER_EMAIL,
+ }
+
+ try:
+ response = (
+ drive_service.permissions()
+ .create(
+ fileId=YOUR_FORM_ID,
+ body=permission_body,
+ sendNotificationEmail=False, # Optional: to avoid sending an email
+ )
+ .execute()
+ )
+ print(
+ f"Added responder {YOUR_RESPONDER_EMAIL}. Permission ID:"
+ f" {response.get('id')}"
+ )
+ print(response)
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+if __name__ == "__main__":
+ add_responder()
+# [END forms_add_responder]
diff --git a/forms/snippets/anyone_with_link_responder.py b/forms/snippets/anyone_with_link_responder.py
new file mode 100644
index 00000000..16257690
--- /dev/null
+++ b/forms/snippets/anyone_with_link_responder.py
@@ -0,0 +1,187 @@
+# Copyright 2025 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.
+
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/drive.file"]
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID and responder's email
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+# [START forms_is_anyone_with_link_responder]
+def is_anyone_with_link_responder():
+ """Checks if anyone with the link is a responder for the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+ anyone_with_link_responder = False
+
+ try:
+ permissions_result = (
+ drive_service.permissions()
+ .list(
+ fileId=YOUR_FORM_ID,
+ fields="permissions(id,type,role,view)",
+ includePermissionsForView="published",
+ )
+ .execute()
+ )
+
+ permissions = permissions_result.get("permissions", [])
+ if not permissions:
+ print(f"No permissions found for form ID: {YOUR_FORM_ID}")
+ else:
+ for permission in permissions:
+ if (
+ permission.get("type") == "anyone"
+ and permission.get("view") == "published"
+ and permission.get("role") == "reader"
+ ):
+ anyone_with_link_responder = True
+ break
+
+ if anyone_with_link_responder:
+ print(
+ f"Form '{YOUR_FORM_ID}' IS configured for 'Anyone with the link' to"
+ " respond."
+ )
+ else:
+ print(
+ f"Form '{YOUR_FORM_ID}' is NOT configured for 'Anyone with the link'"
+ " to respond."
+ )
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return anyone_with_link_responder
+
+
+# [END forms_is_anyone_with_link_responder]
+
+
+# [START forms_set_anyone_with_link_responder]
+def set_anyone_with_link_responder():
+ """Sets anyone with the link to be a responder for the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+
+ permission_body = {
+ "type": "anyone",
+ "view": "published", # Key for making it a responder setting
+ "role": "reader",
+ }
+
+ try:
+ response = (
+ drive_service.permissions()
+ .create(
+ fileId=YOUR_FORM_ID,
+ body=permission_body,
+ )
+ .execute()
+ )
+ print(
+ "'Anyone with the link can respond' permission set for form"
+ f" {YOUR_FORM_ID}: {response}"
+ )
+ return True
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return False
+
+
+# [END forms_set_anyone_with_link_responder]
+
+
+# [START forms_remove_anyone_with_link_responder]
+def remove_anyone_with_link_responder():
+ """Removes anyone with the link as a responder for the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+
+ permission_id_to_delete = None
+
+ try:
+ permissions_result = (
+ drive_service.permissions()
+ .list(
+ fileId=YOUR_FORM_ID,
+ fields="permissions(id,type,role,view)",
+ includePermissionsForView="published",
+ )
+ .execute()
+ )
+
+ permissions = permissions_result.get("permissions", [])
+ for permission in permissions:
+ if (
+ permission.get("type") == "anyone"
+ and permission.get("role") == "reader"
+ and permission.get("view") == "published"
+ ):
+ permission_id_to_delete = permission.get("id")
+ break
+
+ if permission_id_to_delete:
+ drive_service.permissions().delete(
+ fileId=YOUR_FORM_ID, permissionId=permission_id_to_delete
+ ).execute()
+ print(
+ "Successfully removed 'Anyone with the link' permission (ID:"
+ f" {permission_id_to_delete}) from form {YOUR_FORM_ID}."
+ )
+ return True
+ else:
+ print(
+ "'Anyone with the link can respond' permission not found for form"
+ f" {YOUR_FORM_ID}."
+ )
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return False
+
+
+# [END forms_remove_anyone_with_link_responder]
+
+if __name__ == "__main__":
+ is_anyone_with_link_responder()
diff --git a/forms/snippets/convert_form.py b/forms/snippets/convert_form.py
index 2c68d97a..f248b613 100644
--- a/forms/snippets/convert_form.py
+++ b/forms/snippets/convert_form.py
@@ -13,28 +13,30 @@
# limitations under the License.
# [START forms_convert_form]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.body"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-form_service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+form_service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
form = {
"info": {
- "title": "My new form",
+ "title": "My new quiz",
}
}
@@ -46,20 +48,19 @@
"requests": [
{
"updateSettings": {
- "settings": {
- "quizSettings": {
- "isQuiz": True
- }
- },
- "updateMask": "quizSettings.isQuiz"
+ "settings": {"quizSettings": {"isQuiz": True}},
+ "updateMask": "quizSettings.isQuiz",
}
}
]
}
# Converts the form into a quiz
-question_setting = form_service.forms().batchUpdate(formId=result["formId"],
- body=update).execute()
+question_setting = (
+ form_service.forms()
+ .batchUpdate(formId=result["formId"], body=update)
+ .execute()
+)
# Print the result to see it's now a quiz
getresult = form_service.forms().get(formId=result["formId"]).execute()
diff --git a/forms/snippets/create_form.py b/forms/snippets/create_form.py
index ec61385a..9a86e9ae 100644
--- a/forms/snippets/create_form.py
+++ b/forms/snippets/create_form.py
@@ -13,24 +13,26 @@
# limitations under the License.
# [START forms_create_form]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/drive"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-form_service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+form_service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
form = {
"info": {
diff --git a/forms/snippets/create_watch.py b/forms/snippets/create_watch.py
index 8dce58a2..4211e836 100644
--- a/forms/snippets/create_watch.py
+++ b/forms/snippets/create_watch.py
@@ -13,37 +13,35 @@
# limitations under the License.
# [START forms_create_watch]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/drive"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
watch = {
"watch": {
- "target": {
- "topic": {
- "topicName": ""
- }
- },
- "eventType": "RESPONSES"
+ "target": {"topic": {"topicName": ""}},
+ "eventType": "RESPONSES",
}
}
-form_id = ''
+form_id = ""
# Print JSON response after form watch creation
result = service.forms().watches().create(formId=form_id, body=watch).execute()
diff --git a/forms/snippets/delete_watch.py b/forms/snippets/delete_watch.py
index d493cf85..06b40ac0 100644
--- a/forms/snippets/delete_watch.py
+++ b/forms/snippets/delete_watch.py
@@ -13,28 +13,32 @@
# limitations under the License.
# [START forms_delete_watch]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/drive"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
-form_id = ''
-watch_id = ''
+form_id = ""
+watch_id = ""
# Print JSON response after deleting a form watch
-result = service.forms().watches().delete(formId=form_id, watchId=watch_id).execute()
+result = (
+ service.forms().watches().delete(formId=form_id, watchId=watch_id).execute()
+)
print(result)
# [END forms_delete_watch]
diff --git a/forms/snippets/duplicate_form.py b/forms/snippets/duplicate_form.py
index df4ca506..eb49e08a 100644
--- a/forms/snippets/duplicate_form.py
+++ b/forms/snippets/duplicate_form.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START forms_duplicate_form]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -23,38 +21,40 @@
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/drive']
+SCOPES = ["https://www.googleapis.com/auth/drive"]
def main():
- """Shows copy file example in Drive v3 API.
- Prints the name, id and other data of the copied file.
- """
- creds = None
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'client_secrets.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
-
- service = build('drive', 'v3', credentials=creds)
-
- # Call the Drive v3 API
- origin_file_id = '1ox-6vHFeKpC6mon-tL5ygBC8zpbTnTp76JCZdIg80hA' # example ID
- copied_file = {'title': 'my_copy'}
- results = service.files().copy(
- fileId=origin_file_id, body=copied_file).execute()
- print(results)
-
-
-if __name__ == '__main__':
- main()
+ """Shows copy file example in Drive v3 API.
+ Prints the name, id and other data of the copied file.
+ """
+ creds = None
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "client_secrets.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
+
+ service = build("drive", "v3", credentials=creds)
+
+ # Call the Drive v3 API
+ origin_file_id = "1ox-6vHFeKpC6mon-tL5ygBC8zpbTnTp76JCZdIg80hA" # example ID
+ copied_file = {"title": "my_copy"}
+ results = (
+ service.files().copy(fileId=origin_file_id, body=copied_file).execute()
+ )
+ print(results)
+
+
+if __name__ == "__main__":
+ main()
# [END forms_duplicate_form]
diff --git a/forms/snippets/get_responders.py b/forms/snippets/get_responders.py
new file mode 100644
index 00000000..10eca545
--- /dev/null
+++ b/forms/snippets/get_responders.py
@@ -0,0 +1,91 @@
+# Copyright 2025 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.
+
+# [START forms_get_responders]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/drive.metadata.readonly"]
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def get_responders():
+ """Gets the responders for the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+
+ try:
+ response = (
+ drive_service.permissions()
+ .list(
+ fileId=YOUR_FORM_ID,
+ fields="permissions(id,emailAddress,type,role,view)",
+ includePermissionsForView="published",
+ )
+ .execute()
+ )
+
+ published_readers = []
+ for permission in response.get("permissions", []):
+ # 'view': 'published' indicates it's related to the published link.
+ # 'role': 'reader' is standard for responders.
+ # 'type': 'user' for specific users, 'anyone' for public.
+ if (
+ permission.get("view") == "published"
+ and permission.get("role") == "reader"
+ ):
+ published_readers.append(permission)
+
+ if published_readers:
+ print("Responders for this form:")
+ print(published_readers)
+ else:
+ print("No specific published readers found for this form.")
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+if __name__ == "__main__":
+ get_responders()
+# [END forms_get_responders]
diff --git a/forms/snippets/list_watches.py b/forms/snippets/list_watches.py
index 3a48832b..eeb24c11 100644
--- a/forms/snippets/list_watches.py
+++ b/forms/snippets/list_watches.py
@@ -13,25 +13,27 @@
# limitations under the License.
# [START forms_list_form_watches]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/drive"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
-form_id = ''
+form_id = ""
# Print JSON list of form watches
result = service.forms().watches().list(formId=form_id).execute()
diff --git a/forms/snippets/publish_form.py b/forms/snippets/publish_form.py
new file mode 100644
index 00000000..fa6a4fb3
--- /dev/null
+++ b/forms/snippets/publish_form.py
@@ -0,0 +1,86 @@
+# Copyright 2025 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.
+
+# [START forms_publish_form]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/forms.body"]
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def publish_form():
+ """Publishes the form."""
+ creds = get_credentials()
+ form_service = build(
+ "forms",
+ "v1",
+ credentials=creds,
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+ )
+
+ # Request body for updating publish settings
+ set_publish_settings_request = {
+ "publishSettings": {
+ "publishState": {"isPublished": True, "isAcceptingResponses": True}
+ },
+ }
+
+ try:
+ response = (
+ form_service.forms()
+ .setPublishSettings(
+ formId=YOUR_FORM_ID, body=set_publish_settings_request
+ )
+ .execute()
+ )
+ print(f"Form {YOUR_FORM_ID} publish settings updated: {response}")
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+if __name__ == "__main__":
+ publish_form()
+# [END forms_publish_form]
diff --git a/forms/snippets/remove_responder.py b/forms/snippets/remove_responder.py
new file mode 100644
index 00000000..ce5e55b6
--- /dev/null
+++ b/forms/snippets/remove_responder.py
@@ -0,0 +1,101 @@
+# Copyright 2025 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.
+
+# [START forms_remove_responder]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/drive.file"]
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID and responder's email
+YOUR_FORM_ID = "YOUR_FORM_ID"
+YOUR_RESPONDER_EMAIL = "user@example.com"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def remove_responder():
+ """Removes the responder for the form."""
+ creds = get_credentials()
+ drive_service = build("drive", "v3", credentials=creds)
+
+ try:
+ # First, find the permission ID for the user
+ permissions_result = (
+ drive_service.permissions()
+ .list(
+ fileId=YOUR_FORM_ID,
+ fields="permissions(id,emailAddress,role,view,type)",
+ includePermissionsForView="published",
+ )
+ .execute()
+ )
+
+ permission_id_to_delete = None
+ for p in permissions_result.get("permissions", []):
+ if (
+ p.get("emailAddress") == YOUR_RESPONDER_EMAIL
+ and p.get("role") == "reader"
+ and p.get("view") == "published"
+ and p.get("type") == "user"
+ ):
+ permission_id_to_delete = p.get("id")
+ break
+
+ if permission_id_to_delete:
+ drive_service.permissions().delete(
+ fileId=YOUR_FORM_ID, permissionId=permission_id_to_delete
+ ).execute()
+ print(
+ f"Successfully removed responder {YOUR_RESPONDER_EMAIL} (Permission"
+ f" ID: {permission_id_to_delete}) from form {YOUR_FORM_ID}."
+ )
+ else:
+ print(
+ f"Responder {YOUR_RESPONDER_EMAIL} not found or not a published"
+ f" reader for form {YOUR_FORM_ID}."
+ )
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+if __name__ == "__main__":
+ remove_responder()
+# [END forms_remove_responder]
diff --git a/forms/snippets/renew_watch.py b/forms/snippets/renew_watch.py
index 552ed63a..1faeefda 100644
--- a/forms/snippets/renew_watch.py
+++ b/forms/snippets/renew_watch.py
@@ -13,28 +13,32 @@
# limitations under the License.
# [START forms_renew_watch]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/drive"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
-form_id = ''
-watch_id = ''
+form_id = ""
+watch_id = ""
# Print JSON response after renewing a form watch
-result = service.forms().watches().renew(formId=form_id, watchId=watch_id).execute()
+result = (
+ service.forms().watches().renew(formId=form_id, watchId=watch_id).execute()
+)
print(result)
# [END forms_renew_watch]
diff --git a/forms/snippets/retrieve_all_responses.py b/forms/snippets/retrieve_all_responses.py
index 234c7192..0bf9d98c 100644
--- a/forms/snippets/retrieve_all_responses.py
+++ b/forms/snippets/retrieve_all_responses.py
@@ -13,26 +13,28 @@
# limitations under the License.
# [START forms_retrieve_all_responses]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.responses.readonly"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
# Prints the responses of your specified form:
-form_id = ''
+form_id = ""
result = service.forms().responses().list(formId=form_id).execute()
print(result)
# [END forms_retrieve_all_responses]
diff --git a/forms/snippets/retrieve_contents.py b/forms/snippets/retrieve_contents.py
index 83b5e197..1144713e 100644
--- a/forms/snippets/retrieve_contents.py
+++ b/forms/snippets/retrieve_contents.py
@@ -13,26 +13,28 @@
# limitations under the License.
# [START forms_retrieve_contents]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.body.readonly"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
# Prints the title of the sample form:
-form_id = ''
+form_id = ""
result = service.forms().get(formId=form_id).execute()
print(result)
# [END forms_retrieve_contents]
diff --git a/forms/snippets/retrieve_single_response.py b/forms/snippets/retrieve_single_response.py
index c7bd7eb3..757f65f0 100644
--- a/forms/snippets/retrieve_single_response.py
+++ b/forms/snippets/retrieve_single_response.py
@@ -13,28 +13,34 @@
# limitations under the License.
# [START forms_retrieve_single_response]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.responses.readonly"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
-service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
+service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
# Prints the specified response from your form:
-form_id = ''
-response_id = ''
-result = service.forms().responses().get(
- formId=form_id, responseId=response_id).execute()
+form_id = ""
+response_id = ""
+result = (
+ service.forms()
+ .responses()
+ .get(formId=form_id, responseId=response_id)
+ .execute()
+)
print(result)
# [END forms_retrieve_single_response]
diff --git a/forms/snippets/stop_accepting_responses.py b/forms/snippets/stop_accepting_responses.py
new file mode 100644
index 00000000..b7ed29e3
--- /dev/null
+++ b/forms/snippets/stop_accepting_responses.py
@@ -0,0 +1,90 @@
+# Copyright 2025 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.
+
+# [START forms_stop_accepting_responses]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/forms.body"]
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def close_form():
+ """Closes the form for responses."""
+ creds = get_credentials()
+ form_service = build(
+ "forms",
+ "v1",
+ credentials=creds,
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+ )
+
+ stop_accepting_request_body = {
+ "publishSettings": {
+ "publishState": {
+ "isPublished": True, # Keep it published
+ "isAcceptingResponses": False, # But stop accepting responses
+ }
+ }
+ }
+
+ try:
+ response = (
+ form_service.forms()
+ .setPublishSettings( # Corrected: form_service
+ formId=YOUR_FORM_ID, body=stop_accepting_request_body
+ )
+ .execute()
+ )
+ print(f"Form {YOUR_FORM_ID} stopped accepting responses: {response}")
+ return True
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return False
+
+
+if __name__ == "__main__":
+ close_form()
+# [END forms_stop_accepting_responses]
diff --git a/forms/snippets/supports_publishing.py b/forms/snippets/supports_publishing.py
new file mode 100644
index 00000000..37433ab6
--- /dev/null
+++ b/forms/snippets/supports_publishing.py
@@ -0,0 +1,92 @@
+# Copyright 2025 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.
+
+# [START forms_supports_publishing]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/forms.body"]
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def supports_publishing():
+ """Checks if the form supports publishing."""
+ creds = get_credentials()
+ form_service = build(
+ "forms",
+ "v1",
+ credentials=creds,
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+ )
+
+ is_legacy = True # Assume legacy until proven otherwise
+ try:
+ form_metadata = form_service.forms().get(formId=YOUR_FORM_ID).execute()
+ # If 'publishSettings' field exists, it's not a legacy form regarding this feature.
+ if "publishSettings" in form_metadata:
+ print(
+ f"Form '{YOUR_FORM_ID}' (Title:"
+ f" {form_metadata.get('info', {}).get('title')}) is NOT a legacy form"
+ " (supports publishSettings)."
+ )
+ is_legacy = False
+ else:
+ print(
+ f"Form '{YOUR_FORM_ID}' (Title:"
+ f" {form_metadata.get('info', {}).get('title')}) IS a legacy form"
+ " (does not have publishSettings field)."
+ )
+ return not is_legacy # Returns true if it supports publishing
+
+ except Exception as e:
+ print(f"An error occurred while checking form {YOUR_FORM_ID}: {e}")
+ # Depending on the error, it might indicate non-existence or access issues,
+ # not necessarily legacy status.
+ return None
+
+
+if __name__ == "__main__":
+ supports_publishing()
+# [END forms_supports_publishing]
diff --git a/forms/snippets/unpublish_form.py b/forms/snippets/unpublish_form.py
new file mode 100644
index 00000000..3011fbe0
--- /dev/null
+++ b/forms/snippets/unpublish_form.py
@@ -0,0 +1,89 @@
+# Copyright 2025 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.
+
+# [START forms_unpublish_form]
+
+import os.path
+
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+# If modifying these SCOPES, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/forms.body"]
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
+CLIENT_SECRET_FILE = "client_secrets.json"
+TOKEN_FILE = "token.json"
+
+# TODO: Replace with your Form ID
+YOUR_FORM_ID = "YOUR_FORM_ID"
+
+
+def get_credentials():
+ """Gets the credentials for the user."""
+ creds = None
+ if os.path.exists(TOKEN_FILE):
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ CLIENT_SECRET_FILE, SCOPES
+ )
+ creds = flow.run_local_server(port=8080)
+ with open(TOKEN_FILE, "w") as token:
+ token.write(creds.to_json())
+ return creds
+
+
+def unpublish_form():
+ """Unpublishes the form."""
+ creds = get_credentials()
+ form_service = build(
+ "forms",
+ "v1",
+ credentials=creds,
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+ )
+
+ # Request body for updating publish settings
+ set_publish_settings_request = {
+ "publishSettings": {"publishState": {"isPublished": False}},
+ }
+
+ try:
+ response = (
+ form_service.forms()
+ .setPublishSettings(
+ formId=YOUR_FORM_ID, body=set_publish_settings_request
+ )
+ .execute()
+ )
+ print(
+ f"Form {YOUR_FORM_ID} publish settings updated to unpublished:"
+ f" {response}"
+ )
+ return True
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return False
+
+
+if __name__ == "__main__":
+ unpublish_form()
+# [END forms_unpublish_form]
diff --git a/forms/snippets/update_form.py b/forms/snippets/update_form.py
index b11df710..030cacd7 100644
--- a/forms/snippets/update_form.py
+++ b/forms/snippets/update_form.py
@@ -13,24 +13,26 @@
# limitations under the License.
# [START forms_update_form]
-from __future__ import print_function
-
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.body"
-API_KEY = ""
-DISCOVERY_DOC = f"https://forms.googleapis.com/$discovery/rest?version=v1beta&key={API_KEY}&labels=FORMS_BETA_TESTERS"
+DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
-store = file.Storage('credentials.json')
+store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
- creds = tools.run_flow(flow, store)
+ flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
+ creds = tools.run_flow(flow, store)
-form_service = discovery.build('forms', 'v1beta', http=creds.authorize(
- Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
+form_service = discovery.build(
+ "forms",
+ "v1",
+ http=creds.authorize(Http()),
+ discoveryServiceUrl=DISCOVERY_DOC,
+ static_discovery=False,
+)
form = {
"info": {
@@ -43,19 +45,27 @@
# Request body to add description to a Form
update = {
- "requests": [{
- "updateFormInfo": {
- "info": {
- "description": "Please complete this quiz based on this week's readings for class."
- },
- "updateMask": "description"
+ "requests": [
+ {
+ "updateFormInfo": {
+ "info": {
+ "description": (
+ "Please complete this quiz based on this week's"
+ " readings for class."
+ )
+ },
+ "updateMask": "description",
+ }
}
- }]
+ ]
}
# Update the form with a description
-question_setting = form_service.forms().batchUpdate(
- formId=createResult["formId"], body=update).execute()
+question_setting = (
+ form_service.forms()
+ .batchUpdate(formId=createResult["formId"], body=update)
+ .execute()
+)
# Print the result to see it now has a description
getresult = form_service.forms().get(formId=createResult["formId"]).execute()
diff --git a/gmail/quickstart/quickstart.py b/gmail/quickstart/quickstart.py
index 4509faa7..b56e73ad 100644
--- a/gmail/quickstart/quickstart.py
+++ b/gmail/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START gmail_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,49 +22,50 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
+SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
def main():
- """Shows basic usage of the Gmail API.
- Lists the user's Gmail labels.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Gmail API.
+ Lists the user's Gmail labels.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- # Call the Gmail API
- service = build('gmail', 'v1', credentials=creds)
- results = service.users().labels().list(userId='me').execute()
- labels = results.get('labels', [])
+ try:
+ # Call the Gmail API
+ service = build("gmail", "v1", credentials=creds)
+ results = service.users().labels().list(userId="me").execute()
+ labels = results.get("labels", [])
- if not labels:
- print('No labels found.')
- return
- print('Labels:')
- for label in labels:
- print(label['name'])
+ if not labels:
+ print("No labels found.")
+ return
+ print("Labels:")
+ for label in labels:
+ print(label["name"])
- except HttpError as error:
- # TODO(developer) - Handle errors from gmail API.
- print(f'An error occurred: {error}')
+ except HttpError as error:
+ # TODO(developer) - Handle errors from gmail API.
+ print(f"An error occurred: {error}")
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END gmail_quickstart]
diff --git a/gmail/snippet/base_test.py b/gmail/snippet/base_test.py
index f60d12c6..ec0790c4 100644
--- a/gmail/snippet/base_test.py
+++ b/gmail/snippet/base_test.py
@@ -1,3 +1,17 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
import os
import unittest
@@ -6,32 +20,34 @@
class BaseTest(unittest.TestCase):
-
- RECIPIENT = 'gduser01@workspacesamples.dev'
- TEST_USER = 'ci-test01@workspacesamples.dev'
- FORWARDING_ADDRESS = 'gduser01@workspacesamples.dev'
-
- @classmethod
- def setUpClass(cls):
- cls.service = cls.create_service()
-
- @classmethod
- def create_credentials(cls):
- scope = ['https://www.googleapis.com/auth/gmail.compose',
- 'https://www.googleapis.com/auth/gmail.send',
- 'https://www.googleapis.com/auth/gmail.labels',
- 'https://www.googleapis.com/auth/gmail.settings.basic',
- 'https://www.googleapis.com/auth/gmail.settings.sharing',
- 'https://mail.google.com/']
- credentials = ServiceAccountCredentials.from_json_keyfile_name(os.environ['SERVICE_ACCOUNT_CREDENTIALS'],
- scopes=scope)
- return credentials.create_delegated(BaseTest.TEST_USER)
-
- @classmethod
- def create_service(cls):
- credentials = cls.create_credentials()
- return discovery.build('gmail', 'v1', credentials=credentials)
-
-
-if __name__ == '__main__':
- unittest.main()
+ RECIPIENT = "gduser01@workspacesamples.dev"
+ TEST_USER = "ci-test01@workspacesamples.dev"
+ FORWARDING_ADDRESS = "gduser01@workspacesamples.dev"
+
+ @classmethod
+ def setUpClass(cls):
+ cls.service = cls.create_service()
+
+ @classmethod
+ def create_credentials(cls):
+ scope = [
+ "https://www.googleapis.com/auth/gmail.compose",
+ "https://www.googleapis.com/auth/gmail.send",
+ "https://www.googleapis.com/auth/gmail.labels",
+ "https://www.googleapis.com/auth/gmail.settings.basic",
+ "https://www.googleapis.com/auth/gmail.settings.sharing",
+ "https://mail.google.com/",
+ ]
+ credentials = ServiceAccountCredentials.from_json_keyfile_name(
+ os.environ["SERVICE_ACCOUNT_CREDENTIALS"], scopes=scope
+ )
+ return credentials.create_delegated(BaseTest.TEST_USER)
+
+ @classmethod
+ def create_service(cls):
+ credentials = cls.create_credentials()
+ return discovery.build("gmail", "v1", credentials=credentials)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/list_messages.py b/gmail/snippet/list_messages.py
new file mode 100644
index 00000000..d57bd444
--- /dev/null
+++ b/gmail/snippet/list_messages.py
@@ -0,0 +1,76 @@
+# Copyright 2025 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.
+
+# [START gmail_list_messages]
+import os.path
+from google.auth.transport.requests import Request
+from google.oauth2.credentials import Credentials
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+# If modifying these scopes, delete the file token.json.
+SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
+
+
+def main():
+ """Shows basic usage of the Gmail API.
+ Lists the user's Gmail messages.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES)
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
+
+ try:
+ # Call the Gmail API
+ service = build("gmail", "v1", credentials=creds)
+ results = (
+ service.users().messages().list(userId="me", labelIds=["INBOX"]).execute()
+ )
+ messages = results.get("messages", [])
+
+ if not messages:
+ print("No messages found.")
+ return
+
+ print("Messages:")
+ for message in messages:
+ print(f'Message ID: {message["id"]}')
+ msg = (
+ service.users().messages().get(userId="me", id=message["id"]).execute()
+ )
+ print(f' Subject: {msg["snippet"]}')
+
+ except HttpError as error:
+ # TODO(developer) - Handle errors from gmail API.
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ main()
+
+# [END gmail_list_messages]
diff --git a/gmail/snippet/send mail/create_draft.py b/gmail/snippet/send mail/create_draft.py
index 918e9496..5b13f0a3 100644
--- a/gmail/snippet/send mail/create_draft.py
+++ b/gmail/snippet/send mail/create_draft.py
@@ -12,14 +12,11 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
"""
-# [START gmail_create_draft]
-
-from __future__ import print_function
+# [START gmail_create_draft]
import base64
-from email.mime.text import MIMEText
+from email.message import EmailMessage
import google.auth
from googleapiclient.discovery import build
@@ -27,44 +24,49 @@
def gmail_create_draft():
- """Create and insert a draft email.
- Print the returned draft's message and id.
- Returns: Draft object, including draft id and message meta data.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- message = MIMEText('This is automated draft mail')
- message['to'] = 'gduser1@workspacesamples.dev'
- message['from'] = 'gduser2@workspacesamples.dev'
- message['subject'] = 'Automated draft'
- encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
-
- create_message = {
- 'message': {
- 'raw': encoded_message
- }
- }
- # pylint: disable=E1101
- draft = service.users().drafts().create(userId="me",
- body=create_message).execute()
-
- print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
- draft = None
-
- return draft
-
-
-if __name__ == '__main__':
- gmail_create_draft()
+ """Create and insert a draft email.
+ Print the returned draft's message and id.
+ Returns: Draft object, including draft id and message meta data.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ message = EmailMessage()
+
+ message.set_content("This is automated draft mail")
+
+ message["To"] = "gduser1@workspacesamples.dev"
+ message["From"] = "gduser2@workspacesamples.dev"
+ message["Subject"] = "Automated draft"
+
+ # encoded message
+ encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
+
+ create_message = {"message": {"raw": encoded_message}}
+ # pylint: disable=E1101
+ draft = (
+ service.users()
+ .drafts()
+ .create(userId="me", body=create_message)
+ .execute()
+ )
+
+ print(f'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ draft = None
+
+ return draft
+
+
+if __name__ == "__main__":
+ gmail_create_draft()
# [END gmail_create_draft]
diff --git a/gmail/snippet/send mail/create_draft_with_attachment.py b/gmail/snippet/send mail/create_draft_with_attachment.py
index 88d75ded..ba871a23 100644
--- a/gmail/snippet/send mail/create_draft_with_attachment.py
+++ b/gmail/snippet/send mail/create_draft_with_attachment.py
@@ -12,17 +12,15 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_create_draft_with_attachment]
-
-from __future__ import print_function
+# [START gmail_create_draft_with_attachment]
import base64
import mimetypes
import os
+from email.message import EmailMessage
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import google.auth
@@ -31,78 +29,90 @@
def gmail_create_draft_with_attachment():
- """Create and insert a draft email with attachment.
- Print the returned draft's message and id.
- Returns: Draft object, including draft id and message meta data.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
- mime_message = MIMEMultipart()
- mime_message['to'] = 'gduser1@workspacesamples.dev'
- mime_message['from'] = 'gduser2@workspacesamples.dev'
- mime_message['subject'] = 'sample with attachment'
- text_part = MIMEText('Hi, this is automated mail with attachment.'
- 'Please do not reply.')
- mime_message.attach(text_part)
- image_attachment = build_file_part(file='photo.jpg')
- mime_message.attach(image_attachment)
- encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()).decode()
-
- create_draft_request_body = {
- 'message': {
- 'raw': encoded_message
- }
- }
- # pylint: disable=E1101
- draft = service.users().drafts().create(userId="me",
- body=create_draft_request_body)\
- .execute()
- print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
- except HttpError as error:
- print(F'An error occurred: {error}')
- draft = None
- return draft
+ """Create and insert a draft email with attachment.
+ Print the returned draft's message and id.
+ Returns: Draft object, including draft id and message meta data.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+ mime_message = EmailMessage()
+
+ # headers
+ mime_message["To"] = "gduser1@workspacesamples.dev"
+ mime_message["From"] = "gduser2@workspacesamples.dev"
+ mime_message["Subject"] = "sample with attachment"
+
+ # text
+ mime_message.set_content(
+ "Hi, this is automated mail with attachment.Please do not reply."
+ )
+
+ # attachment
+ attachment_filename = "photo.jpg"
+ # guessing the MIME type
+ type_subtype, _ = mimetypes.guess_type(attachment_filename)
+ maintype, subtype = type_subtype.split("/")
+
+ with open(attachment_filename, "rb") as fp:
+ attachment_data = fp.read()
+ mime_message.add_attachment(attachment_data, maintype, subtype)
+
+ encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()).decode()
+
+ create_draft_request_body = {"message": {"raw": encoded_message}}
+ # pylint: disable=E1101
+ draft = (
+ service.users()
+ .drafts()
+ .create(userId="me", body=create_draft_request_body)
+ .execute()
+ )
+ print(f'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ draft = None
+ return draft
def build_file_part(file):
- """Creates a MIME part for a file.
-
- Args:
- file: The path to the file to be attached.
-
- Returns:
- A MIME part that can be attached to a message.
- """
- content_type, encoding = mimetypes.guess_type(file)
-
- if content_type is None or encoding is not None:
- content_type = 'application/octet-stream'
- main_type, sub_type = content_type.split('/', 1)
- if main_type == 'text':
- with open(file, 'rb'):
- msg = MIMEText('r', _subtype=sub_type)
- elif main_type == 'image':
- with open(file, 'rb'):
- msg = MIMEImage('r', _subtype=sub_type)
- elif main_type == 'audio':
- with open(file, 'rb'):
- msg = MIMEAudio('r', _subtype=sub_type)
- else:
- with open(file, 'rb'):
- msg = MIMEBase(main_type, sub_type)
- msg.set_payload(file.read())
- filename = os.path.basename(file)
- msg.add_header('Content-Disposition', 'attachment', filename=filename)
- return msg
-
-
-if __name__ == '__main__':
- gmail_create_draft_with_attachment()
- # [END gmail_create_draft_with_attachment]
+ """Creates a MIME part for a file.
+
+ Args:
+ file: The path to the file to be attached.
+
+ Returns:
+ A MIME part that can be attached to a message.
+ """
+ content_type, encoding = mimetypes.guess_type(file)
+
+ if content_type is None or encoding is not None:
+ content_type = "application/octet-stream"
+ main_type, sub_type = content_type.split("/", 1)
+ if main_type == "text":
+ with open(file, "rb"):
+ msg = MIMEText("r", _subtype=sub_type)
+ elif main_type == "image":
+ with open(file, "rb"):
+ msg = MIMEImage("r", _subtype=sub_type)
+ elif main_type == "audio":
+ with open(file, "rb"):
+ msg = MIMEAudio("r", _subtype=sub_type)
+ else:
+ with open(file, "rb"):
+ msg = MIMEBase(main_type, sub_type)
+ msg.set_payload(file.read())
+ filename = os.path.basename(file)
+ msg.add_header("Content-Disposition", "attachment", filename=filename)
+ return msg
+
+
+if __name__ == "__main__":
+ gmail_create_draft_with_attachment()
+ # [END gmail_create_draft_with_attachment]
diff --git a/gmail/snippet/send mail/send_message.py b/gmail/snippet/send mail/send_message.py
index dd19c41b..697f922e 100644
--- a/gmail/snippet/send mail/send_message.py
+++ b/gmail/snippet/send mail/send_message.py
@@ -10,12 +10,10 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_send_message]
-
-from __future__ import print_function
+# [START gmail_send_message]
import base64
-from email.mime.text import MIMEText
+from email.message import EmailMessage
import google.auth
from googleapiclient.discovery import build
@@ -23,42 +21,44 @@
def gmail_send_message():
- """Create and send an email message
- Print the returned message id
- Returns: Message object, including message id
+ """Create and send an email message
+ Print the returned message id
+ Returns: Message object, including message id
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ service = build("gmail", "v1", credentials=creds)
+ message = EmailMessage()
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
+ message.set_content("This is automated draft mail")
- try:
- service = build('gmail', 'v1', credentials=creds)
- message = MIMEText('This is automated draft mail')
- message['to'] = 'gduser1@workspacesamples.dev'
- message['from'] = 'gduser2@workspacesamples.dev'
- message['subject'] = 'Automated draft'
- # encoded message
- encoded_message = base64.urlsafe_b64encode(message.as_bytes()) \
- .decode()
+ message["To"] = "gduser1@workspacesamples.dev"
+ message["From"] = "gduser2@workspacesamples.dev"
+ message["Subject"] = "Automated draft"
- create_message = {
- 'message': {
+ # encoded message
+ encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
- 'raw': encoded_message
- }
- }
- # pylint: disable=E1101
- send_message = (service.users().messages().send
- (userId="me", body=create_message).execute())
- print(F'Message Id: {send_message["id"]}')
- except HttpError as error:
- print(F'An error occurred: {error}')
- send_message = None
- return send_message
+ create_message = {"raw": encoded_message}
+ # pylint: disable=E1101
+ send_message = (
+ service.users()
+ .messages()
+ .send(userId="me", body=create_message)
+ .execute()
+ )
+ print(f'Message Id: {send_message["id"]}')
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ send_message = None
+ return send_message
-if __name__ == '__main__':
- gmail_send_message()
+if __name__ == "__main__":
+ gmail_send_message()
# [END gmail_send_message]
diff --git a/gmail/snippet/send mail/send_message_with_attachment.py b/gmail/snippet/send mail/send_message_with_attachment.py
deleted file mode 100644
index a8832250..00000000
--- a/gmail/snippet/send mail/send_message_with_attachment.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""
-Copyright 2019 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.
-"""
-# [START gmail_send_message_with_attachment]
-from __future__ import print_function
-
-import base64
-import mimetypes
-import os
-from email.mime.audio import MIMEAudio
-from email.mime.base import MIMEBase
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
-import google.auth
-from googleapiclient.discovery import build
-from googleapiclient.errors import HttpError
-
-
-def gmail_send_message_with_attachment():
- """Create and send an email message with attachment
- Print the returned message id
- Returns: Message object, including message id
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- service = build('gmail', 'v1', credentials=creds)
- mime_message = MIMEMultipart()
- mime_message['to'] = 'gduser1@workspacesamples.dev'
- mime_message['from'] = 'gduser2@workspacesamples.dev'
- mime_message['subject'] = 'sample with attachment'
- text_part = MIMEText('Hi, this is automated mail with attachment.'
- 'Please do not reply.')
- mime_message.attach(text_part)
- image_attachment = build_file_part(file='photo.jpg')
- mime_message.attach(image_attachment)
- # encoded message
- encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()) \
- .decode()
-
- send_message_request_body = {
- 'message': {
-
- 'raw': encoded_message
- }
- }
- # pylint: disable=E1101
- send_message = (service.users().messages().send
- (userId='me', body=send_message_request_body).execute())
- print(F'Message Id: {send_message["id"]}')
- except HttpError as error:
- print(F'An error occurred: {error}')
- send_message = None
- return send_message
-
-
-def build_file_part(file):
- """Creates a MIME part for a file.
- Args:
- file: The path to the file to be attached.
- Returns:
- A MIME part that can be attached to a message.
- """
- content_type, encoding = mimetypes.guess_type(file)
- if content_type is None or encoding is not None:
- content_type = 'application/octet-stream'
- main_type, sub_type = content_type.split('/', 1)
- if main_type == 'text':
- with open(file, 'rb'):
- msg = MIMEText('r', _subtype=sub_type)
- elif main_type == 'image':
- with open(file, 'rb'):
- msg = MIMEImage('r', _subtype=sub_type)
- elif main_type == 'audio':
- with open(file, 'rb'):
- msg = MIMEAudio('r', _subtype=sub_type)
- else:
- with open(file, 'rb'):
- msg = MIMEBase(main_type, sub_type)
- msg.set_payload(file.read())
- filename = os.path.basename(file)
- msg.add_header('Content-Disposition', 'attachment', filename=filename)
- return msg
-
-
-if __name__ == '__main__':
- gmail_send_message_with_attachment()
-# [END gmail_send_message_with_attachment]
diff --git a/gmail/snippet/send mail/test_create_draft.py b/gmail/snippet/send mail/test_create_draft.py
new file mode 100644
index 00000000..f8636c1f
--- /dev/null
+++ b/gmail/snippet/send mail/test_create_draft.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from create_draft import gmail_create_draft
+
+
+class TestCreateDraft(unittest.TestCase):
+ """Unit test class for snippet"""
+
+ @classmethod
+ def test_create_draft(cls):
+ """Unit test for create draft"""
+ draft = gmail_create_draft()
+ cls.assertIsNotNone(cls, draft)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/send mail/test_create_draft_with_attachment.py b/gmail/snippet/send mail/test_create_draft_with_attachment.py
new file mode 100644
index 00000000..502c813e
--- /dev/null
+++ b/gmail/snippet/send mail/test_create_draft_with_attachment.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from create_draft_with_attachment import gmail_create_draft_with_attachment
+
+
+class TestCreateDraftWithAttachment(unittest.TestCase):
+ """Unit test class for Change snippet"""
+
+ @classmethod
+ def test_create_draft_with_attachment(cls):
+ """Test create draft with attachment"""
+ draft = gmail_create_draft_with_attachment()
+ cls.assertIsNotNone(cls, draft)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/send mail/test_send_message.py b/gmail/snippet/send mail/test_send_message.py
new file mode 100644
index 00000000..3aecfb65
--- /dev/null
+++ b/gmail/snippet/send mail/test_send_message.py
@@ -0,0 +1,31 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from send_message import gmail_send_message
+
+
+class TestSendMessage(unittest.TestCase):
+ """Unit test class for snippet"""
+
+ def test_send_message(self):
+ """test send message"""
+ send_message = gmail_send_message()
+ self.assertIsNotNone(self, send_message)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/send mail/test_send_message_with_attachment.py b/gmail/snippet/send mail/test_send_message_with_attachment.py
new file mode 100644
index 00000000..79cfe0f5
--- /dev/null
+++ b/gmail/snippet/send mail/test_send_message_with_attachment.py
@@ -0,0 +1,31 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from send_message_with_attachment import gmail_send_message_with_attachment
+
+
+class TestSendMessageWithAttachment(unittest.TestCase):
+ """Unit test class for gmail snippet"""
+
+ def test_send_message_with_attachment(self):
+ """test send message with attachment"""
+ send_message = gmail_send_message_with_attachment()
+ self.assertIsNotNone(self, send_message)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/send_mail.py b/gmail/snippet/send_mail.py
deleted file mode 100644
index 2724a0ae..00000000
--- a/gmail/snippet/send_mail.py
+++ /dev/null
@@ -1,146 +0,0 @@
-"""Send an email message from the user's account.
-"""
-
-import base64
-import mimetypes
-import os
-from email.mime.audio import MIMEAudio
-from email.mime.base import MIMEBase
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
-from apiclient import errors
-
-
-# [START create_draft]
-def create_draft(service, user_id, message_body):
- """Create and insert a draft email. Print the returned draft's message and id.
-
- Args:
- service: Authorized Gmail API service instance.
- user_id: User's email address. The special value "me"
- can be used to indicate the authenticated user.
- message_body: The body of the email message, including headers.
-
- Returns:
- Draft object, including draft id and message meta data.
- """
- try:
- message = {'message': message_body}
- draft = service.users().drafts().create(userId=user_id, body=message).execute()
-
- print('Draft id: %s\nDraft message: %s' % (draft['id'], draft['message']))
-
- return draft
- except errors.HttpError as error:
- print('An error occurred: %s' % error)
- return None
-
-
-# [END create_draft]
-
-
-# [START send_email]
-def send_message(service, user_id, message):
- """Send an email message.
-
- Args:
- service: Authorized Gmail API service instance.
- user_id: User's email address. The special value "me"
- can be used to indicate the authenticated user.
- message: Message to be sent.
-
- Returns:
- Sent Message.
- """
- try:
- message = (service.users().messages().send(userId=user_id, body=message)
- .execute())
- print('Message Id: %s' % message['id'])
- return message
- except errors.HttpError as error:
- print('An error occurred: %s' % error)
-
-
-# [END send_email]
-
-
-# [START create_message]
-def create_message(sender, to, subject, message_text):
- """Create a message for an email.
-
- Args:
- sender: Email address of the sender.
- to: Email address of the receiver.
- subject: The subject of the email message.
- message_text: The text of the email message.
-
- Returns:
- An object containing a base64url encoded email object.
- """
- message = MIMEText(message_text)
- message['to'] = to
- message['from'] = sender
- message['subject'] = subject
-
- encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
-
- return {'raw': encoded_message}
-
-
-# [END create_message]
-
-
-# [START create_message_attachment]
-def create_message_with_attachment(
- sender, to, subject, message_text, file):
- """Create a message for an email.
-
- Args:
- sender: Email address of the sender.
- to: Email address of the receiver.
- subject: The subject of the email message.
- message_text: The text of the email message.
- file: The path to the file to be attached.
-
- Returns:
- An object containing a base64url encoded email object.
- """
- message = MIMEMultipart()
- message['to'] = to
- message['from'] = sender
- message['subject'] = subject
-
- msg = MIMEText(message_text)
- message.attach(msg)
-
- content_type, encoding = mimetypes.guess_type(file)
-
- if content_type is None or encoding is not None:
- content_type = 'application/octet-stream'
- main_type, sub_type = content_type.split('/', 1)
- if main_type == 'text':
- fp = open(file, 'rb')
- msg = MIMEText(fp.read(), _subtype=sub_type)
- fp.close()
- elif main_type == 'image':
- fp = open(file, 'rb')
- msg = MIMEImage(fp.read(), _subtype=sub_type)
- fp.close()
- elif main_type == 'audio':
- fp = open(file, 'rb')
- msg = MIMEAudio(fp.read(), _subtype=sub_type)
- fp.close()
- else:
- fp = open(file, 'rb')
- msg = MIMEBase(main_type, sub_type)
- msg.set_payload(fp.read())
- fp.close()
- filename = os.path.basename(file)
- msg.add_header('Content-Disposition', 'attachment', filename=filename)
- message.attach(msg)
-
- encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
- return {'raw': encoded_message}
-# [END create_message_attachment]
diff --git a/gmail/snippet/settings snippets/create_filter.py b/gmail/snippet/settings snippets/create_filter.py
index 17508392..3531e2c5 100644
--- a/gmail/snippet/settings snippets/create_filter.py
+++ b/gmail/snippet/settings snippets/create_filter.py
@@ -12,52 +12,53 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_create_filter]
-
-from __future__ import print_function
+# [START gmail_create_filter]
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def create_filter():
- """Create a filter.
- Returns: Draft object, including filter id.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- label_name = 'IMPORTANT'
- filter_content = {
- 'criteria': {
- 'from': 'gsuder1@workspacesamples.dev'
- },
- 'action': {
- 'addLabelIds': [label_name],
- 'removeLabelIds': ['INBOX']
- }
- }
-
- # pylint: disable=E1101
- result = service.users().settings().filters().create(
- userId='me', body=filter_content).execute()
- print(F'Created filter with id: {result.get("id")}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
- result = None
-
- return result.get('id')
-
-
-if __name__ == '__main__':
- create_filter()
+ """Create a filter.
+ Returns: Draft object, including filter id.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ label_name = "IMPORTANT"
+ filter_content = {
+ "criteria": {"from": "gsuder1@workspacesamples.dev"},
+ "action": {
+ "addLabelIds": [label_name],
+ "removeLabelIds": ["INBOX"],
+ },
+ }
+
+ # pylint: disable=E1101
+ result = (
+ service.users()
+ .settings()
+ .filters()
+ .create(userId="me", body=filter_content)
+ .execute()
+ )
+ print(f'Created filter with id: {result.get("id")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ result = None
+
+ return result.get("id")
+
+
+if __name__ == "__main__":
+ create_filter()
# [END gmail_create_filter]
diff --git a/gmail/snippet/settings snippets/enable_auto_reply.py b/gmail/snippet/settings snippets/enable_auto_reply.py
index 69bd727c..fa9f3425 100644
--- a/gmail/snippet/settings snippets/enable_auto_reply.py
+++ b/gmail/snippet/settings snippets/enable_auto_reply.py
@@ -12,10 +12,8 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_enable_auto_reply]
-
-from __future__ import print_function
+# [START gmail_enable_auto_reply]
from datetime import datetime, timedelta
import google.auth
@@ -25,45 +23,50 @@
def enable_auto_reply():
- """Enable auto reply.
- Returns:Draft object, including reply message and response meta data.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- epoch = datetime.utcfromtimestamp(0)
- now = datetime.now()
- start_time = (now - epoch).total_seconds() * 1000
- end_time = (now + timedelta(days=7) - epoch).total_seconds() * 1000
- vacation_settings = {
- 'enableAutoReply': True,
- 'responseBodyHtml': "I am on vacation and will reply when I am "
- "back in the office. Thanks!",
- 'restrictToDomain': True,
- 'startTime': long(start_time),
- 'endTime': long(end_time)
- }
-
- # pylint: disable=E1101
- response = service.users().settings().updateVacation(
- userId='me', body=vacation_settings).execute()
- print(F'Enabled AutoReply with message: '
- F'{response.get("responseBodyHtml")}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
- response = None
-
- return response
-
-
-if __name__ == '__main__':
- enable_auto_reply()
+ """Enable auto reply.
+ Returns:Draft object, including reply message and response meta data.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ epoch = datetime.utcfromtimestamp(0)
+ now = datetime.now()
+ start_time = (now - epoch).total_seconds() * 1000
+ end_time = (now + timedelta(days=7) - epoch).total_seconds() * 1000
+ vacation_settings = {
+ "enableAutoReply": True,
+ "responseBodyHtml": (
+ "I am on vacation and will reply when I am "
+ "back in the office. Thanks!"
+ ),
+ "restrictToDomain": True,
+ "startTime": long(start_time),
+ "endTime": long(end_time),
+ }
+
+ # pylint: disable=E1101
+ response = (
+ service.users()
+ .settings()
+ .updateVacation(userId="me", body=vacation_settings)
+ .execute()
+ )
+ print(f"Enabled AutoReply with message: {response.get('responseBodyHtml')}")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ response = None
+
+ return response
+
+
+if __name__ == "__main__":
+ enable_auto_reply()
# [END gmail_enable_auto_reply]
diff --git a/gmail/snippet/settings snippets/enable_forwarding.py b/gmail/snippet/settings snippets/enable_forwarding.py
index 97f63157..17e4b80f 100644
--- a/gmail/snippet/settings snippets/enable_forwarding.py
+++ b/gmail/snippet/settings snippets/enable_forwarding.py
@@ -12,52 +12,59 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_enable_forwarding]
-
-from __future__ import print_function
+# [START gmail_enable_forwarding]
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def enable_forwarding():
- """Enable email forwarding.
- Returns:Draft object, including forwarding id and result meta data.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- address = {'forwardingEmail': 'gduser1@workspacesamples.dev'}
-
- # pylint: disable=E1101
- result = service.users().settings().forwardingAddresses(). \
- create(userId='me', body=address).execute()
- if result.get('verificationStatus') == 'accepted':
- body = {
- 'emailAddress': result.get('forwardingEmail'),
- 'enabled': True,
- 'disposition': 'trash'
- }
- # pylint: disable=E1101
- result = service.users().settings().updateAutoForwarding(
- userId='me', body=body).execute()
- print(F'Forwarding is enabled : {result}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
- result = None
-
- return result
-
-
-if __name__ == '__main__':
- enable_forwarding()
+ """Enable email forwarding.
+ Returns:Draft object, including forwarding id and result meta data.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ address = {"forwardingEmail": "gduser1@workspacesamples.dev"}
+
+ # pylint: disable=E1101
+ result = (
+ service.users()
+ .settings()
+ .forwardingAddresses()
+ .create(userId="me", body=address)
+ .execute()
+ )
+ if result.get("verificationStatus") == "accepted":
+ body = {
+ "emailAddress": result.get("forwardingEmail"),
+ "enabled": True,
+ "disposition": "trash",
+ }
+ # pylint: disable=E1101
+ result = (
+ service.users()
+ .settings()
+ .updateAutoForwarding(userId="me", body=body)
+ .execute()
+ )
+ print(f"Forwarding is enabled : {result}")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ result = None
+
+ return result
+
+
+if __name__ == "__main__":
+ enable_forwarding()
# [END gmail_enable_forwarding]
diff --git a/gmail/snippet/settings snippets/test_create_filter.py b/gmail/snippet/settings snippets/test_create_filter.py
new file mode 100644
index 00000000..27a4abe8
--- /dev/null
+++ b/gmail/snippet/settings snippets/test_create_filter.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from create_filter import create_filter
+
+
+class TestCreateFilter(unittest.TestCase):
+ """Unit test class to implement test case for Snippets"""
+
+ @classmethod
+ def test_create_file(cls):
+ """test to create file"""
+ result = create_filter()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/settings snippets/test_enable_auto_reply.py b/gmail/snippet/settings snippets/test_enable_auto_reply.py
new file mode 100644
index 00000000..92873a8a
--- /dev/null
+++ b/gmail/snippet/settings snippets/test_enable_auto_reply.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from enable_auto_reply import enable_auto_reply
+
+
+class TestEnableAutoReply(unittest.TestCase):
+ """Unit test class for the snippet"""
+
+ @classmethod
+ def test_enable_auto_reply(cls):
+ """test to enable auto reply"""
+ result = enable_auto_reply()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/settings snippets/test_enable_forwarding.py b/gmail/snippet/settings snippets/test_enable_forwarding.py
new file mode 100644
index 00000000..22411e23
--- /dev/null
+++ b/gmail/snippet/settings snippets/test_enable_forwarding.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from enable_forwarding import enable_forwarding
+
+
+class TestEnableForwarding(unittest.TestCase):
+ """Unit test class to test enable forwarding snippet"""
+
+ @classmethod
+ def test_enable_forwarding(cls):
+ """test to enable forwarding"""
+ result = enable_forwarding()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/settings snippets/test_update_signature.py b/gmail/snippet/settings snippets/test_update_signature.py
new file mode 100644
index 00000000..71a60c7a
--- /dev/null
+++ b/gmail/snippet/settings snippets/test_update_signature.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from update_signature import update_signature
+
+
+class TestUpdateSignature(unittest.TestCase):
+ """Unit test class to test Update signature snippet"""
+
+ @classmethod
+ def test_update_signature(cls):
+ """test to update signature"""
+ result = update_signature()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/settings snippets/update_signature.py b/gmail/snippet/settings snippets/update_signature.py
index bfa93c37..b0711616 100644
--- a/gmail/snippet/settings snippets/update_signature.py
+++ b/gmail/snippet/settings snippets/update_signature.py
@@ -12,57 +12,62 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_update_signature]
-
-from __future__ import print_function
+# [START gmail_update_signature]
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def update_signature():
- """Create and update signature in gmail.
- Returns:Draft object, including updated signature.
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- primary_alias = None
-
- # pylint: disable=E1101
- aliases = service.users().settings().sendAs().list(userId='me')\
- .execute()
- for alias in aliases.get('sendAs'):
- if alias.get('isPrimary'):
- primary_alias = alias
- break
-
- send_as_configuration = {
- 'displayName': primary_alias.get('sendAsEmail'),
- 'signature': 'Automated Signature'
- }
-
- # pylint: disable=E1101
- result = service.users().settings().sendAs() \
- .patch(userId='me', sendAsEmail=primary_alias.get('sendAsEmail'),
- body=send_as_configuration).execute()
- print(F'Updated signature for: {result.get("displayName")}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
- result = None
-
- return result.get('signature')
-
-
-if __name__ == '__main__':
- update_signature()
+ """Create and update signature in gmail.
+ Returns:Draft object, including updated signature.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ primary_alias = None
+
+ # pylint: disable=E1101
+ aliases = service.users().settings().sendAs().list(userId="me").execute()
+ for alias in aliases.get("sendAs"):
+ if alias.get("isPrimary"):
+ primary_alias = alias
+ break
+
+ send_as_configuration = {
+ "displayName": primary_alias.get("sendAsEmail"),
+ "signature": "Automated Signature",
+ }
+
+ # pylint: disable=E1101
+ result = (
+ service.users()
+ .settings()
+ .sendAs()
+ .patch(
+ userId="me",
+ sendAsEmail=primary_alias.get("sendAsEmail"),
+ body=send_as_configuration,
+ )
+ .execute()
+ )
+ print(f'Updated signature for: {result.get("displayName")}')
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ result = None
+
+ return result.get("signature")
+
+
+if __name__ == "__main__":
+ update_signature()
# [END gmail_update_signature]
diff --git a/gmail/snippet/settings_snippets.py b/gmail/snippet/settings_snippets.py
deleted file mode 100644
index 30addfa6..00000000
--- a/gmail/snippet/settings_snippets.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from datetime import datetime, timedelta
-
-from numpy import long
-
-
-class SettingsSnippets:
-
- def __init__(self, service):
- self.service = service
-
- def update_signature(self):
- gmail_service = self.service
- # [START updateSignature]
- primary_alias = None
- aliases = gmail_service.users().settings().sendAs(). \
- list(userId='me').execute()
- for alias in aliases.get('sendAs'):
- if alias.get('isPrimary'):
- primary_alias = alias
- break
-
- sendAsConfiguration = {
- 'signature': 'I heart cats'
- }
- result = gmail_service.users().settings().sendAs(). \
- patch(userId='me',
- sendAsEmail=primary_alias.get('sendAsEmail'),
- body=sendAsConfiguration).execute()
- print('Updated signature for: %s' % result.get('displayName'))
- # [END updateSignature]
- return result.get('signature')
-
- def create_filter(self, real_label_id):
- gmail_service = self.service
- # [START createFilter]
- label_id = 'Label_14' # ID of user label to add
- # [START_EXCLUDE silent]
- label_id = real_label_id
- # [END_EXCLUDE]
- filter = {
- 'criteria': {
- 'from': 'cat-enthusiasts@example.com'
- },
- 'action': {
- 'addLabelIds': [label_id],
- 'removeLabelIds': ['INBOX']
- }
- }
- result = gmail_service.users().settings().filters(). \
- create(userId='me', body=filter).execute()
- print('Created filter: %s' % result.get('id'))
- # [END createFilter]
- return result.get('id')
-
- def enable_forwarding(self, real_forwarding_address):
- gmail_service = self.service
- # [START enableForwarding]
- address = {
- 'forwardingEmail': 'user2@example.com'
- }
- # [START_EXCLUDE silent]
- address = {
- 'forwardingEmail': real_forwarding_address
- }
- # [END_EXCLUDE]
- result = gmail_service.users().settings().forwardingAddresses(). \
- create(userId='me', body=address).execute()
- if result.get('verificationStatus') == 'accepted':
- body = {
- 'emailAddress': result.get('forwardingEmail'),
- 'enabled': True,
- 'disposition': 'trash'
- }
- result = gmail_service.users().settings(). \
- updateAutoForwarding(userId='me', body=body).execute()
- # [START_EXCLUDE silent]
- return result
- # [END_EXCLUDE]
-
- # [END enableForwarding]
- return None
-
- def enable_auto_reply(self):
- gmail_service = self.service
- # [START enableAutoReply]
- epoch = datetime.utcfromtimestamp(0)
- now = datetime.now()
- start_time = (now - epoch).total_seconds() * 1000
- end_time = (now + timedelta(days=7) - epoch).total_seconds() * 1000
- vacation_settings = {
- 'enableAutoReply': True,
- 'responseBodyHtml': "I'm on vacation and will reply when I'm "
- "back in the office. Thanks!",
- 'restrictToDomain': True,
- 'startTime': long(start_time),
- 'endTime': long(end_time)
- }
- response = gmail_service.users().settings(). \
- updateVacation(userId='me', body=vacation_settings).execute()
- # [END enableAutoReply]
- return response
diff --git a/gmail/snippet/smime snippets/create_smime_info.py b/gmail/snippet/smime snippets/create_smime_info.py
index ba66e5ae..90c4325a 100644
--- a/gmail/snippet/smime snippets/create_smime_info.py
+++ b/gmail/snippet/smime snippets/create_smime_info.py
@@ -9,38 +9,36 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_create_smime_info]
-
-from __future__ import print_function
+# [START gmail_create_smime_info]
import base64
def create_smime_info(cert_filename, cert_password):
- """Create an smimeInfo resource for a certificate from file.
- Args:
- cert_filename: Name of the file containing the S/MIME certificate.
- cert_password: Password for the certificate file, or None if the file is not
- password-protected.
- Returns : Smime object, including smime information
- """
-
+ """Create an smimeInfo resource for a certificate from file.
+ Args:
+ cert_filename: Name of the file containing the S/MIME certificate.
+ cert_password: Password for the certificate file, or None if the file is not
+ password-protected.
+ Returns : Smime object, including smime information
+ """
+
+ smime_info = None
+ try:
+ with open(cert_filename, "rb") as cert:
+ smime_info = {}
+ data = cert.read().encode("UTF-8")
+ smime_info["pkcs12"] = base64.urlsafe_b64encode(data).decode()
+ if cert_password and len(cert_password) > 0:
+ smime_info["encryptedKeyPassword"] = cert_password
+
+ except (OSError, IOError) as error:
+ print(f"An error occurred while reading the certificate file: {error}")
smime_info = None
- try:
- with open(cert_filename, 'rb') as cert:
- smime_info = {}
- data = cert.read().encode('UTF-8')
- smime_info['pkcs12'] = base64.urlsafe_b64encode(data).decode()
- if cert_password and len(cert_password) > 0:
- smime_info['encryptedKeyPassword'] = cert_password
-
- except (OSError, IOError) as error:
- print(F'An error occurred while reading the certificate file: {error}')
- smime_info = None
- return smime_info
+ return smime_info
-if __name__ == '__main__':
- print(create_smime_info(cert_filename='xyz', cert_password='xyz'))
+if __name__ == "__main__":
+ print(create_smime_info(cert_filename="xyz", cert_password="xyz"))
# [END gmail_create_smime_info]
diff --git a/gmail/snippet/smime snippets/insert_cert_from_csv.py b/gmail/snippet/smime snippets/insert_cert_from_csv.py
new file mode 100644
index 00000000..d07fc2fa
--- /dev/null
+++ b/gmail/snippet/smime snippets/insert_cert_from_csv.py
@@ -0,0 +1,52 @@
+"""Copyright 2018 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.
+"""
+
+# [START gmail_insert_cert_from_csv]
+import csv
+
+import create_smime_info
+import insert_smime_info
+
+
+def insert_cert_from_csv(csv_filename):
+ """Upload S/MIME certificates based on the contents of a CSV file.
+ Each row of the CSV file should contain a user ID, path to the certificate,
+ and the certificate password.
+
+ Args:
+ csv_filename: Name of the CSV file.
+ """
+
+ try:
+ with open(csv_filename, "rb") as cert:
+ csv_reader = csv.reader(cert, delimiter=",")
+ next(csv_reader, None) # skip CSV file header
+ for row in csv_reader:
+ user_id = row[0]
+ cert_filename = row[1]
+ cert_password = row[2]
+ smime_info = create_smime_info.create_smime_info(
+ cert_filename=cert_filename, cert_password=cert_password
+ )
+ if smime_info:
+ insert_smime_info.insert_smime_info()
+ else:
+ print(f"Unable to read certificate file for user_id: {user_id}")
+ return smime_info
+
+ except (OSError, IOError) as error:
+ print(f"An error occured while reading the CSV file: {error}")
+
+
+if __name__ == "__main__":
+ insert_cert_from_csv(csv_filename="xyz")
+# [END gmail_insert_cert_from_csv]
diff --git a/gmail/snippet/smime snippets/insert_smime_info.py b/gmail/snippet/smime snippets/insert_smime_info.py
index 46a8fe8e..19540ad7 100644
--- a/gmail/snippet/smime snippets/insert_smime_info.py
+++ b/gmail/snippet/smime snippets/insert_smime_info.py
@@ -9,10 +9,8 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_insert_smime_info]
-
-from __future__ import print_function
+# [START gmail_insert_smime_info]
import create_smime_info
import google.auth
from googleapiclient.discovery import build
@@ -20,40 +18,47 @@
def insert_smime_info():
- """Upload an S/MIME certificate for the user.
- Print the inserted certificate's id
- Returns : Result object with inserted certificate id and other meta-data
+ """Upload an S/MIME certificate for the user.
+ Print the inserted certificate's id
+ Returns : Result object with inserted certificate id and other meta-data
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
- user_id = 'gduser1@workspacesamples.dev'
- smime_info = create_smime_info.create_smime_info(cert_filename='xyz', cert_password='xyz')
- send_as_email = None
+ user_id = "gduser1@workspacesamples.dev"
+ smime_info = create_smime_info.create_smime_info(
+ cert_filename="xyz", cert_password="xyz"
+ )
+ send_as_email = None
- if not send_as_email:
- send_as_email = user_id
+ if not send_as_email:
+ send_as_email = user_id
- # pylint: disable=maybe-no-member
- results = service.users().settings().sendAs().smimeInfo().\
- insert(userId=user_id, sendAsEmail=send_as_email, body=smime_info)\
- .execute()
- print(F'Inserted certificate; id: {results["id"]}')
+ # pylint: disable=maybe-no-member
+ results = (
+ service.users()
+ .settings()
+ .sendAs()
+ .smimeInfo()
+ .insert(userId=user_id, sendAsEmail=send_as_email, body=smime_info)
+ .execute()
+ )
+ print(f'Inserted certificate; id: {results["id"]}')
- except HttpError as error:
- print(F'An error occurred: {error}')
- results = None
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ results = None
- return results
+ return results
-if __name__ == '__main__':
- insert_smime_info()
+if __name__ == "__main__":
+ insert_smime_info()
# [END gmail_insert_smime_info]
diff --git a/gmail/snippet/smime snippets/test_create_smime_info.py b/gmail/snippet/smime snippets/test_create_smime_info.py
new file mode 100644
index 00000000..d5a1f278
--- /dev/null
+++ b/gmail/snippet/smime snippets/test_create_smime_info.py
@@ -0,0 +1,33 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from create_smime_info import create_smime_info
+
+
+class TestCreateSmimeInfo(unittest.TestCase):
+ """Unit test class to test Snippet"""
+
+ @classmethod
+ def test_create_smime_info(cls):
+ """test to create smime info"""
+ # enter the file and password accordingly
+ smime_info = create_smime_info(cert_filename="abc", cert_password="abc")
+ cls.assertIsNotNone(cls, smime_info)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/smime snippets/test_insert_cert_from_csv.py b/gmail/snippet/smime snippets/test_insert_cert_from_csv.py
new file mode 100644
index 00000000..4d728d2b
--- /dev/null
+++ b/gmail/snippet/smime snippets/test_insert_cert_from_csv.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from insert_cert_from_csv import insert_cert_from_csv
+
+
+class TestInsertCertFromCsv(unittest.TestCase):
+ """unittest class for testing the snippetts"""
+
+ @classmethod
+ def test_insert_cert_from_csv(cls):
+ """test to insert cert from csv"""
+ result = insert_cert_from_csv("test.csv")
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/smime snippets/test_insert_smime_info.py b/gmail/snippet/smime snippets/test_insert_smime_info.py
new file mode 100644
index 00000000..3478fcf7
--- /dev/null
+++ b/gmail/snippet/smime snippets/test_insert_smime_info.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from insert_smime_info import insert_smime_info
+
+
+class TestInsertSmimeInfo(unittest.TestCase):
+ """Unit test class for snippet"""
+
+ @classmethod
+ def test_insert_smime_info(cls):
+ """test to insert smime info"""
+ result = insert_smime_info()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/smime snippets/test_update_smime_cert.py b/gmail/snippet/smime snippets/test_update_smime_cert.py
new file mode 100644
index 00000000..54343b28
--- /dev/null
+++ b/gmail/snippet/smime snippets/test_update_smime_cert.py
@@ -0,0 +1,38 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from update_smime_cert import update_smime_cert
+
+
+class TestUpdateSmimeCert(unittest.TestCase):
+ """Unit test class for snippets"""
+
+ @classmethod
+ def test_update_smime_cert(cls):
+ """test update smime cert"""
+ result = update_smime_cert(
+ user_id="xyz",
+ send_as_email="yzx",
+ cert_filename="abc",
+ cert_password="abc",
+ expire_dt="cde",
+ )
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/smime snippets/test_update_smime_from_csv.py b/gmail/snippet/smime snippets/test_update_smime_from_csv.py
new file mode 100644
index 00000000..f03d082f
--- /dev/null
+++ b/gmail/snippet/smime snippets/test_update_smime_from_csv.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from update_smime_from_csv import update_smime_from_csv
+
+
+class TestUpdateSmimeFromCsv(unittest.TestCase):
+ """unit test class for snippets"""
+
+ @classmethod
+ def test_update_smime_from_csv(cls):
+ """test to update smime from csv"""
+ result = update_smime_from_csv(csv_filename="abc")
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/smime snippets/update_smime_cert.py b/gmail/snippet/smime snippets/update_smime_cert.py
new file mode 100644
index 00000000..34d72ded
--- /dev/null
+++ b/gmail/snippet/smime snippets/update_smime_cert.py
@@ -0,0 +1,126 @@
+"""Copyright 2018 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.
+"""
+
+# [START gmail_update_smime_certs]
+from datetime import datetime
+
+import create_smime_info
+import google.auth
+import insert_smime_info
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def update_smime_cert(
+ user_id, send_as_email, cert_filename, cert_password, expire_dt
+):
+ """Update S/MIME certificates for the user.
+
+ First performs a lookup of all certificates for a user. If there are no
+ certificates, or they all expire before the specified date/time, uploads the
+ certificate in the specified file. If the default certificate is expired or
+ there was no default set, chooses the certificate with the expiration furthest
+ into the future and sets it as default.
+
+ Args:
+ user_id: User's email address.
+ send_as_email: The "send as" email address, or None if it should be the same
+ as user_id.
+ cert_filename: Name of the file containing the S/MIME certificate.
+ cert_password: Password for the certificate file, or None if the file is not
+ password-protected.
+ expire_dt: DateTime object against which the certificate expiration is
+ compared. If None, uses the current time.
+
+ Returns:
+ The ID of the default certificate.
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ if not send_as_email:
+ send_as_email = user_id
+
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ results = (
+ service.users()
+ .settings()
+ .sendAs()
+ .smimeInfo()
+ .list(userId=user_id, sendAsEmail=send_as_email)
+ .execute()
+ )
+
+ except HttpError as error:
+ print(f"An error occurred during list: {error}")
+ return None
+
+ default_cert_id = None
+ best_cert_id = (None, datetime.datetime.fromtimestamp(0))
+
+ if not expire_dt:
+ expire_dt = datetime.datetime.now()
+ if results and "smimeInfo" in results:
+ for smime_info in results["smimeInfo"]:
+ cert_id = smime_info["id"]
+ is_default_cert = smime_info["isDefault"]
+ if is_default_cert:
+ default_cert_id = cert_id
+ exp = datetime.datetime.fromtimestamp(smime_info["expiration"] / 1000)
+ if exp > expire_dt:
+ if exp > best_cert_id[1]:
+ best_cert_id = (cert_id, exp)
+ else:
+ if is_default_cert:
+ default_cert_id = None
+
+ if not default_cert_id:
+ default_id = best_cert_id[0]
+ if not default_id and cert_filename:
+ create_smime_info.create_smime_info(
+ cert_filename=cert_filename, cert_password=cert_password
+ )
+ results = insert_smime_info.insert_smime_info()
+ if results:
+ default_id = results["id"]
+
+ if default_id:
+ try:
+ # pylint: disable=maybe-no-member
+ service.users().settings().sendAs().smimeInfo().setDefault(
+ userId=user_id, sendAsEmail=send_as_email, id=default_id
+ ).execute()
+ return default_id
+ except HttpError as error:
+ print(f"An error occurred during setDefault: {error}")
+ else:
+ return default_cert_id
+
+ return None
+
+
+if __name__ == "__main__":
+ update_smime_cert(
+ user_id="xyz",
+ send_as_email=None,
+ cert_filename="xyz",
+ cert_password="xyz",
+ expire_dt=None,
+ )
+# [END gmail_update_smime_certs]
diff --git a/gmail/snippet/smime snippets/update_smime_from_csv.py b/gmail/snippet/smime snippets/update_smime_from_csv.py
new file mode 100644
index 00000000..6e38e07f
--- /dev/null
+++ b/gmail/snippet/smime snippets/update_smime_from_csv.py
@@ -0,0 +1,52 @@
+"""Copyright 2018 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.
+"""
+
+# [START gmail_update_smime_from_csv]
+import csv
+
+import update_smime_cert
+
+
+# pylint: disable-this-line-in-some-way
+def update_smime_from_csv(csv_filename, expire_dt=None):
+ """Update S/MIME certificates based on the contents of a CSV file.
+
+ Each row of the CSV file should contain a user ID, path to the certificate,
+ and the certificate password.
+
+ Args:
+ csv_filename: Name of the CSV file.
+ expire_dt: DateTime object against which the certificate expiration is
+ compared. If None, uses the current time.
+ """
+ ret0 = ""
+ try:
+ with open(csv_filename, "rb") as cert:
+ csv_reader = csv.reader(cert, delimiter=",")
+ next(csv_reader, None) # skip CSV file header
+ for row in csv_reader:
+ user_id = row[0]
+ ret0 = update_smime_cert.update_smime_cert(
+ user_id,
+ send_as_email=user_id,
+ cert_filename=row[1],
+ cert_password=row[2],
+ expire_dt=expire_dt,
+ )
+ return ret0
+ except (OSError, IOError) as error:
+ print(f"An error occured while reading the CSV file: {error}")
+
+
+if __name__ == "__main__":
+ update_smime_from_csv(csv_filename="xyz")
+# [END gmail_update_smime_from_csv]
diff --git a/gmail/snippet/smime_snippets.py b/gmail/snippet/smime_snippets.py
deleted file mode 100644
index 6cc30818..00000000
--- a/gmail/snippet/smime_snippets.py
+++ /dev/null
@@ -1,203 +0,0 @@
-"""Snippets for managing S/MIME certificate for a user's account.
-
-These snippets appear at:
-https://developers.google.com/gmail/api/guides/smime_certs
-"""
-import base64
-import csv
-import datetime
-
-from apiclient import errors
-
-
-# [START create_smime_info]
-def create_smime_info(cert_filename, cert_password=None):
- """Create an smimeInfo resource for a certificate from file.
-
- Args:
- cert_filename: Name of the file containing the S/MIME certificate.
- cert_password: Password for the certificate file, or None if the file is not
- password-protected.
- """
- smime_info = None
- try:
- with open(cert_filename, 'r') as f:
- smime_info = {}
- data = f.read().encode('UTF-8')
- smime_info['pkcs12'] = base64.urlsafe_b64encode(data)
- if cert_password and len(cert_password) > 0:
- smime_info['encryptedKeyPassword'] = cert_password
- except (OSError, IOError) as error:
- print('An error occurred while reading the certificate file: %s' % error)
-
- return smime_info
-
-
-# [END create_smime_info]
-
-
-# [START insert_smime_info]
-def insert_smime_info(service, user_id, smime_info, send_as_email=None):
- """Upload an S/MIME certificate for the user.
-
- Args:
- service: Authorized GMail API service instance.
- user_id: User's email address.
- smime_info: The smimeInfo resource containing the user's S/MIME certificate.
- send_as_email: The "send as" email address, or None if it should be the same
- as user_id.
- """
- if not send_as_email:
- send_as_email = user_id
- try:
- results = service.users().settings().sendAs().smimeInfo().insert(
- userId=user_id, sendAsEmail=send_as_email, body=smime_info).execute()
- print('Inserted certificate; id: %s' % results['id'])
- return results
- except errors.HttpError as error:
- print('An error occurred: %s' % error)
- return None
-
-
-# [END insert_smime_info]
-
-
-# [START insert_cert_from_csv]
-def insert_cert_from_csv(service_builder, csv_filename):
- """Upload S/MIME certificates based on the contents of a CSV file.
-
- Each row of the CSV file should contain a user ID, path to the certificate,
- and the certificate password.
-
- Args:
- service_builder: A function that returns an authorized GMail API service
- instance for a given user.
- csv_filename: Name of the CSV file.
- """
- try:
- with open(csv_filename, 'r') as f:
- csv_reader = csv.reader(f, delimiter=',')
- next(csv_reader, None) # skip CSV file header
- for row in csv_reader:
- user_id = row[0]
- cert_filename = row[1]
- cert_password = row[2]
- smime_info = create_smime_info(cert_filename, cert_password)
- if smime_info:
- insert_smime_info(service_builder(user_id), user_id, smime_info)
- else:
- print('Unable to read certificate file for user_id: %s' % user_id)
- except (OSError, IOError) as error:
- print('An error occured while reading the CSV file: %s' % error)
-
-
-# [END insert_cert_from_csv]
-
-
-# [START update_smime_certs]
-def update_smime_certs(service,
- user_id,
- send_as_email=None,
- cert_filename=None,
- cert_password=None,
- expire_dt=None):
- """Update S/MIME certificates for the user.
-
- First performs a lookup of all certificates for a user. If there are no
- certificates, or they all expire before the specified date/time, uploads the
- certificate in the specified file. If the default certificate is expired or
- there was no default set, chooses the certificate with the expiration furthest
- into the future and sets it as default.
-
- Args:
- service: Authorized GMail API service instance.
- user_id: User's email address.
- send_as_email: The "send as" email address, or None if it should be the same
- as user_id.
- cert_filename: Name of the file containing the S/MIME certificate.
- cert_password: Password for the certificate file, or None if the file is not
- password-protected.
- expire_dt: DateTime object against which the certificate expiration is
- compared. If None, uses the current time.
-
- Returns:
- The ID of the default certificate.
- """
- if not send_as_email:
- send_as_email = user_id
-
- try:
- results = service.users().settings().sendAs().smimeInfo().list(
- userId=user_id, sendAsEmail=send_as_email).execute()
- except errors.HttpError as error:
- print('An error occurred during list: %s' % error)
- return None
-
- default_cert_id = None
- best_cert_id = (None, datetime.datetime.fromtimestamp(0))
-
- if not expire_dt:
- expire_dt = datetime.datetime.now()
- if results and 'smimeInfo' in results:
- for smime_info in results['smimeInfo']:
- cert_id = smime_info['id']
- is_default_cert = smime_info['isDefault']
- if is_default_cert:
- default_cert_id = cert_id
- exp = datetime.datetime.fromtimestamp(smime_info['expiration'] / 1000)
- if exp > expire_dt:
- if exp > best_cert_id[1]:
- best_cert_id = (cert_id, exp)
- else:
- if is_default_cert:
- default_cert_id = None
-
- if not default_cert_id:
- default_id = best_cert_id[0]
- if not default_id and cert_filename:
- smime_info = create_smime_info(cert_filename, cert_password)
- results = insert_smime_info(service, user_id, smime_info)
- if results:
- default_id = results['id']
-
- if default_id:
- try:
- service.users().settings().sendAs().smimeInfo().setDefault(
- userId=user_id, sendAsEmail=send_as_email, id=default_id).execute()
- return default_id
- except errors.HttpError as error:
- print('An error occurred during setDefault: %s' % error)
- else:
- return default_cert_id
-
- return None
-
-
-def update_smime_from_csv(service_builder, csv_filename, expire_dt=None):
- """Update S/MIME certificates based on the contents of a CSV file.
-
- Each row of the CSV file should contain a user ID, path to the certificate,
- and the certificate password.
-
- Args:
- service_builder: A function that returns an authorized GMail API service
- instance for a given user.
- csv_filename: Name of the CSV file.
- expire_dt: DateTime object against which the certificate expiration is
- compared. If None, uses the current time.
- """
- try:
- with open(csv_filename, 'r') as f:
- csv_reader = csv.reader(f, delimiter=',')
- next(csv_reader, None) # skip CSV file header
- for row in csv_reader:
- user_id = row[0]
- update_smime_certs(
- service_builder(user_id),
- user_id,
- cert_filename=row[1],
- cert_password=row[2],
- expire_dt=expire_dt)
- except (OSError, IOError) as error:
- print('An error occured while reading the CSV file: %s' % error)
-# [END update_smime_certs]
diff --git a/gmail/snippet/test_send_mail.py b/gmail/snippet/test_send_mail.py
deleted file mode 100644
index e29c7771..00000000
--- a/gmail/snippet/test_send_mail.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import unittest
-
-import send_mail
-from base_test import BaseTest
-
-
-class SendMailTest(BaseTest):
- @classmethod
- def setUpClass(cls):
- super(SendMailTest, cls).setUpClass()
-
- def setUp(self):
- super(SendMailTest, self).setUp()
-
- def tearDown(self):
- super(SendMailTest, self).tearDown()
-
- def test_create_message(self):
- message = send_mail.create_message(SendMailTest.TEST_USER,
- SendMailTest.RECIPIENT,
- 'Test',
- 'Hello!')
- self.assertIsNotNone(message) # Weak assertion
-
- def test_create_message_with_attachment(self):
- message = send_mail.create_message_with_attachment(SendMailTest.TEST_USER,
- SendMailTest.RECIPIENT,
- 'Test',
- 'Hello!',
- 'files/photo.jpg')
- self.assertIsNotNone(message) # Weak assertion
-
- def test_create_draft(self):
- message = send_mail.create_message(SendMailTest.TEST_USER,
- SendMailTest.RECIPIENT,
- 'Test',
- 'Hello!')
- draft = send_mail.create_draft(self.service, 'me', message)
- self.assertIsNotNone(draft)
- self.service.users().drafts().delete(userId='me', id=draft.get('id'))
-
- def test_send_mail(self):
- message = send_mail.create_message_with_attachment(SendMailTest.TEST_USER,
- SendMailTest.RECIPIENT,
- 'Test',
- 'Hello!',
- 'files/photo.jpg')
- sent_message = send_mail.send_message(self.service, 'me', message)
- self.assertIsNotNone(sent_message)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gmail/snippet/test_settings_snippets.py b/gmail/snippet/test_settings_snippets.py
deleted file mode 100644
index 95bd72d0..00000000
--- a/gmail/snippet/test_settings_snippets.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import unittest
-
-from base_test import BaseTest
-from settings_snippets import SettingsSnippets
-
-
-class SettingsSnippetsTest(BaseTest):
-
- @classmethod
- def setUpClass(cls):
- super(SettingsSnippetsTest, cls).setUpClass()
- cls.snippets = SettingsSnippets(cls.service)
-
- def setUp(self):
- super(SettingsSnippetsTest, self).setUp()
-
- def tearDown(self):
- super(SettingsSnippetsTest, self).tearDown()
-
- def create_test_label(self):
- labels = self.service.users().labels().list(userId='me').execute()
- for label in labels.get('labels'):
- if label.get('name') == 'testLabel':
- return label
-
- body = {
- 'name': 'testLabel',
- 'labelListVisibility': 'labelShow',
- 'messageListVisibility': 'show'
- }
- return self.service.users().labels().create(userId='me', body=body).execute()
-
- def test_update_signature(self):
- signature = self.snippets.update_signature()
- self.assertIsNotNone(signature)
-
- def test_create_filter(self):
- test_label = self.create_test_label()
- id = self.snippets.create_filter(test_label.get('id'))
- self.assertIsNotNone(id)
- self.service.users().settings().filters().delete(userId='me', id=id).execute()
- self.service.users().labels().delete(userId='me', id=test_label.get('id'))
-
- def test_enable_auto_forwarding(self):
- forwarding = self.snippets.enable_forwarding(BaseTest.FORWARDING_ADDRESS)
- self.assertIsNotNone(forwarding)
- body = {
- 'enabled': False,
- }
- self.service.users().settings().updateAutoForwarding(userId='me', body=body).execute()
- self.service.users().settings().forwardingAddresses().delete(
- userId='me', forwardingEmail=BaseTest.FORWARDING_ADDRESS).execute()
-
- def test_enable_auto_reply(self):
- settings = self.snippets.enable_auto_reply()
- self.assertIsNotNone(settings)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gmail/snippet/test_smime_snippets.py b/gmail/snippet/test_smime_snippets.py
deleted file mode 100644
index 65d790d0..00000000
--- a/gmail/snippet/test_smime_snippets.py
+++ /dev/null
@@ -1,368 +0,0 @@
-import datetime
-import unittest
-from unittest import mock
-
-import httplib2
-import smime_snippets
-from apiclient import errors
-
-
-class SmimeSnippetsTest(unittest.TestCase):
- CURRENT_TIME = 1234567890
- TEST_USER = 'user1@example.com'
-
- @classmethod
- def setUpClass(cls):
- pass
-
- def setUp(self):
- self.mock_delete = mock.Mock()
- self.mock_get = mock.Mock()
- self.mock_insert = mock.Mock()
- self.mock_list = mock.Mock()
- self.mock_set_default = mock.Mock()
-
- self.mock_service = mock.Mock()
- self.mock_service.users.return_value = self.mock_service
- self.mock_service.settings.return_value = self.mock_service
- self.mock_service.sendAs.return_value = self.mock_service
- self.mock_service.smimeInfo.return_value = self.mock_service
-
- self.mock_service.delete = self.mock_delete
- self.mock_service.get = self.mock_get
- self.mock_service.insert = self.mock_insert
- self.mock_service.list = self.mock_list
- self.mock_service.setDefault = self.mock_set_default
-
- def tearDown(self):
- # The delete() and get() API methods are not used and should not be called.
- self.mock_delete.assert_not_called()
- self.mock_get.assert_not_called()
-
- @staticmethod
- def make_fake_insert_result(id='new_certificate_id',
- is_default=False,
- expiration=CURRENT_TIME + 1):
- """Construct a fake result of calling insert() on the S/MIME API.
-
- By default, the certificate expires after CURRENT_TIME.
- """
- return {
- 'id': id,
- 'isDefault': is_default,
- 'expiration': expiration * 1000,
- 'issuerCn': 'fake_authority',
- 'pem': 'fake_certificate_contents',
- }
-
- def make_fake_list_result(self,
- is_default=[False],
- expiration=[CURRENT_TIME + 1]):
- """Construct a fake result of calling list() on the S/MIME API.
-
- No more than one of the values in is_default may be True.
- By default, each certificate expires after CURRENT_TIME.
- """
- self.assertEqual(len(is_default), len(expiration))
- self.assertLessEqual(is_default.count(True), 1)
- smime_info = []
- id_base = 'existing_certificate_id_%d'
- for i in range(len(is_default)):
- smime_info.append(
- self.make_fake_insert_result(
- id=(id_base % i),
- is_default=is_default[i],
- expiration=expiration[i]))
- return {'smimeInfo': smime_info}
-
- @staticmethod
- def make_http_error(status, reason):
- """Construct a fake HttpError thrown by the API."""
- response = httplib2.Response({'status': status})
- response.reason = reason
- return errors.HttpError(resp=response, content=b'')
-
- def test_create_smime_info(self):
- smime_info = smime_snippets.create_smime_info('files/cert.p12')
-
- self.assertIsNotNone(smime_info)
- self.assertListEqual(list(smime_info.keys()), ['pkcs12'])
- self.assertGreater(len(smime_info['pkcs12']), 0)
-
- def test_create_smime_info_with_password(self):
- smime_info = smime_snippets.create_smime_info('files/cert.p12', 'password')
-
- self.assertIsNotNone(smime_info)
- self.assertSetEqual(
- set(smime_info.keys()), set(['pkcs12', 'encryptedKeyPassword']))
- self.assertGreater(len(smime_info['pkcs12']), 0)
- self.assertEqual(smime_info['encryptedKeyPassword'], 'password')
-
- def test_create_smime_info_file_not_found(self):
- smime_info = smime_snippets.create_smime_info('files/notfound.p12')
-
- self.mock_insert.assert_not_called()
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertIsNone(smime_info)
-
- def test_insert_smime_info(self):
- insert_result = self.make_fake_insert_result()
- self.mock_insert.return_value = mock.Mock(
- **{'execute.return_value': insert_result})
-
- smime_info = smime_snippets.create_smime_info('files/cert.p12')
- result = smime_snippets.insert_smime_info(self.mock_service, self.TEST_USER,
- smime_info)
-
- self.mock_insert.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER, body=smime_info)
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertEqual(result, insert_result)
-
- def test_insert_smime_info_error(self):
- fake_error = self.make_http_error(500, 'Fake Error')
- self.mock_insert.side_effect = fake_error
-
- smime_info = smime_snippets.create_smime_info('files/cert.p12')
- result = smime_snippets.insert_smime_info(
- self.mock_service, self.TEST_USER, smime_info, 'user1alias@example.com')
-
- self.mock_insert.assert_called_with(
- userId=self.TEST_USER,
- sendAsEmail='user1alias@example.com',
- body=smime_info)
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertIsNone(result)
-
- def test_insert_cert_from_csv(self):
- self.mock_insert.return_value = mock.Mock(
- **{'execute.return_value': self.make_fake_insert_result()})
-
- smime_snippets.insert_cert_from_csv(lambda x: self.mock_service,
- 'files/certs.csv')
-
- self.assertListEqual(self.mock_insert.call_args_list, [
- mock.call(
- userId='user1@example.com',
- sendAsEmail='user1@example.com',
- body=mock.ANY),
- mock.call(
- userId='user2@example.com',
- sendAsEmail='user2@example.com',
- body=mock.ANY)
- ])
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- def test_insert_cert_from_csv_fails(self):
- smime_snippets.insert_cert_from_csv(lambda x: self.mock_service,
- 'files/notfound.csv')
-
- self.mock_insert.assert_not_called()
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- def test_update_smime_certs_no_certs(self):
- self.mock_list.return_value = mock.Mock(**{'execute.return_value': None})
-
- default_cert_id = smime_snippets.update_smime_certs(self.mock_service,
- self.TEST_USER)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_insert.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertIsNone(default_cert_id)
-
- def test_update_smime_certs_no_certs_upload_new_cert(self):
- self.mock_list.return_value = mock.Mock(**{'execute.return_value': None})
- self.mock_insert.return_value = mock.Mock(
- **{'execute.return_value': self.make_fake_insert_result()})
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service, self.TEST_USER, cert_filename='files/cert.p12')
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_insert.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER, body=mock.ANY)
- self.mock_set_default.assert_called_with(
- userId=self.TEST_USER,
- sendAsEmail=self.TEST_USER,
- id='new_certificate_id')
-
- self.assertEqual(default_cert_id, 'new_certificate_id')
-
- def test_update_smime_certs_valid_default_cert_no_upload(self):
- expire_dt = datetime.datetime.fromtimestamp(self.CURRENT_TIME)
- fake_list_result = self.make_fake_list_result(is_default=[True])
- self.mock_list.return_value = mock.Mock(
- **{'execute.return_value': fake_list_result})
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service,
- self.TEST_USER,
- cert_filename='files/cert.p12',
- expire_dt=expire_dt)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_insert.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertEqual(default_cert_id, 'existing_certificate_id_0')
-
- def test_update_smime_certs_expired_default_cert_upload_new_cert(self):
- expire_dt = datetime.datetime.fromtimestamp(self.CURRENT_TIME + 2)
- fake_list_result = self.make_fake_list_result(is_default=[True])
- self.mock_list.return_value = mock.Mock(
- **{'execute.return_value': fake_list_result})
- self.mock_insert.return_value = mock.Mock(
- **{'execute.return_value': self.make_fake_insert_result()})
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service,
- self.TEST_USER,
- cert_filename='files/cert.p12',
- expire_dt=expire_dt)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_insert.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER, body=mock.ANY)
- self.mock_set_default.assert_called_with(
- userId=self.TEST_USER,
- sendAsEmail=self.TEST_USER,
- id='new_certificate_id')
-
- self.assertEqual(default_cert_id, 'new_certificate_id')
-
- def test_update_smime_certs_default_cert_expired_other_cert_new_default(self):
- expire_dt = datetime.datetime.fromtimestamp(self.CURRENT_TIME)
- fake_list_result = self.make_fake_list_result(
- is_default=[True, False],
- expiration=[self.CURRENT_TIME - 1, self.CURRENT_TIME + 1])
- self.mock_list.return_value = mock.Mock(
- **{'execute.return_value': fake_list_result})
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service,
- self.TEST_USER,
- cert_filename='files/cert.p12',
- expire_dt=expire_dt)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_set_default.assert_called_with(
- userId=self.TEST_USER,
- sendAsEmail=self.TEST_USER,
- id='existing_certificate_id_1')
- self.mock_insert.assert_not_called()
-
- self.assertEqual(default_cert_id, 'existing_certificate_id_1')
-
- def test_update_smime_certs_no_defaults_choose_best_cert_as_new_default(self):
- expire_dt = datetime.datetime.fromtimestamp(self.CURRENT_TIME)
- fake_list_result = self.make_fake_list_result(
- is_default=[False, False, False, False],
- expiration=[
- self.CURRENT_TIME + 2, self.CURRENT_TIME + 1, self.CURRENT_TIME + 4,
- self.CURRENT_TIME + 3
- ])
- self.mock_list.return_value = mock.Mock(
- **{'execute.return_value': fake_list_result})
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service,
- self.TEST_USER,
- cert_filename='files/cert.p12',
- expire_dt=expire_dt)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_set_default.assert_called_with(
- userId=self.TEST_USER,
- sendAsEmail=self.TEST_USER,
- id='existing_certificate_id_2')
- self.mock_insert.assert_not_called()
-
- self.assertEqual(default_cert_id, 'existing_certificate_id_2')
-
- def test_update_smime_certs_error(self):
- expire_dt = datetime.datetime.fromtimestamp(self.CURRENT_TIME)
- fake_error = self.make_http_error(500, 'Fake Error')
- self.mock_list.side_effect = fake_error
-
- default_cert_id = smime_snippets.update_smime_certs(
- self.mock_service,
- self.TEST_USER,
- cert_filename='files/cert.p12',
- expire_dt=expire_dt)
-
- self.mock_list.assert_called_with(
- userId=self.TEST_USER, sendAsEmail=self.TEST_USER)
- self.mock_insert.assert_not_called()
- self.mock_set_default.assert_not_called()
-
- self.assertIsNone(default_cert_id)
-
- def test_update_smime_from_csv(self):
- self.mock_list.return_value = mock.Mock(**{'execute.return_value': None})
- self.mock_insert.return_value = mock.Mock(
- **{'execute.return_value': self.make_fake_insert_result()})
-
- smime_snippets.update_smime_from_csv(lambda x: self.mock_service,
- 'files/certs.csv')
-
- self.assertListEqual(self.mock_list.call_args_list, [
- mock.call(userId='user1@example.com', sendAsEmail='user1@example.com'),
- mock.call(userId='user2@example.com', sendAsEmail='user2@example.com'),
- mock.call(userId='user3@example.com', sendAsEmail='user3@example.com'),
- ])
- self.assertListEqual(self.mock_insert.call_args_list, [
- mock.call(
- userId='user1@example.com',
- sendAsEmail='user1@example.com',
- body=mock.ANY),
- mock.call(
- userId='user2@example.com',
- sendAsEmail='user2@example.com',
- body=mock.ANY),
- mock.call(
- userId='user3@example.com',
- sendAsEmail='user3@example.com',
- body=mock.ANY)
- ])
- self.assertListEqual(self.mock_set_default.call_args_list, [
- mock.call(
- userId='user1@example.com',
- sendAsEmail='user1@example.com',
- id='new_certificate_id'),
- mock.call(
- userId='user2@example.com',
- sendAsEmail='user2@example.com',
- id='new_certificate_id'),
- mock.call(
- userId='user3@example.com',
- sendAsEmail='user3@example.com',
- id='new_certificate_id'),
- ])
-
- def test_update_smime_from_csv_fails(self):
- smime_snippets.update_smime_from_csv(lambda x: self.mock_service,
- 'files/notfound.csv')
-
- self.mock_insert.assert_not_called()
- self.mock_list.assert_not_called()
- self.mock_set_default.assert_not_called()
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gmail/snippet/test_threads.py b/gmail/snippet/test_threads.py
deleted file mode 100644
index db39ace2..00000000
--- a/gmail/snippet/test_threads.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import unittest
-
-import threads
-from base_test import BaseTest
-
-
-class ThreadsTest(BaseTest):
- @classmethod
- def setUpClass(cls):
- super(ThreadsTest, cls).setUpClass()
-
- def setUp(self):
- super(ThreadsTest, self).setUp()
-
- def tearDown(self):
- super(ThreadsTest, self).tearDown()
-
- def test_show_chatty_threads(self):
- # TODO - Capture output and assert
- threads.show_chatty_threads(self.service)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gmail/snippet/test_update_signature.py b/gmail/snippet/test_update_signature.py
deleted file mode 100644
index ac85a078..00000000
--- a/gmail/snippet/test_update_signature.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import unittest
-
-from base_test import BaseTest
-from settings_snippets import SettingsSnippets
-
-
-class SettingsSnippetsTest(BaseTest):
-
- @classmethod
- def setUpClass(cls):
- super(SettingsSnippetsTest, cls).setUpClass()
- cls.snippets = SettingsSnippets(cls.service)
-
- def setUp(self):
- super(SettingsSnippetsTest, self).setUp()
-
- def tearDown(self):
- super(SettingsSnippetsTest, self).tearDown()
-
- def test_update_signature(self):
- signature = self.snippets.update_signature()
- self.assertIsNotNone(signature)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gmail/snippet/thread/test_thread.py b/gmail/snippet/thread/test_thread.py
new file mode 100644
index 00000000..a365fa28
--- /dev/null
+++ b/gmail/snippet/thread/test_thread.py
@@ -0,0 +1,32 @@
+"""Copyright 2022 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+from threads import show_chatty_threads
+
+
+class TestThreads(unittest.TestCase):
+ """unit test class for snippets"""
+
+ @classmethod
+ def test_threads(cls):
+ """to test threads"""
+ result = show_chatty_threads()
+ cls.assertIsNotNone(cls, result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/gmail/snippet/thread/threads.py b/gmail/snippet/thread/threads.py
index 9df8bcd5..973316a3 100644
--- a/gmail/snippet/thread/threads.py
+++ b/gmail/snippet/thread/threads.py
@@ -9,50 +9,54 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
-# [START gmail_show_chatty_threads]
-
-from __future__ import print_function
+# [START gmail_show_chatty_threads]
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def show_chatty_threads():
- """Display threads with long conversations(>= 3 messages)
- Return: None
-
- Load pre-authorized user credentials from the environment.
- TODO(developer) - See https://developers.google.com/identity
- for guides on implementing OAuth2 for the application.
- """
- creds, _ = google.auth.default()
-
- try:
- # create gmail api client
- service = build('gmail', 'v1', credentials=creds)
-
- # pylint: disable=maybe-no-member
- threads = service.users().threads().list(userId='me').execute().get('threads', [])
- for thread in threads:
- tdata = service.users().threads().get(userId='me', id=thread['id']).execute()
- nmsgs = len(tdata['messages'])
-
- # skip if <3 msgs in thread
- if nmsgs > 2:
- msg = tdata['messages'][0]['payload']
- subject = ''
- for header in msg['headers']:
- if header['name'] == 'Subject':
- subject = header['value']
- break
- if subject: # skip if no Subject line
- print(F'- {subject}, {nmsgs}')
-
- except HttpError as error:
- print(F'An error occurred: {error}')
-
-
-if __name__ == '__main__':
- show_chatty_threads()
+ """Display threads with long conversations(>= 3 messages)
+ Return: None
+
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+
+ try:
+ # create gmail api client
+ service = build("gmail", "v1", credentials=creds)
+
+ # pylint: disable=maybe-no-member
+ # pylint: disable:R1710
+ threads = (
+ service.users().threads().list(userId="me").execute().get("threads", [])
+ )
+ for thread in threads:
+ tdata = (
+ service.users().threads().get(userId="me", id=thread["id"]).execute()
+ )
+ nmsgs = len(tdata["messages"])
+
+ # skip if <3 msgs in thread
+ if nmsgs > 2:
+ msg = tdata["messages"][0]["payload"]
+ subject = ""
+ for header in msg["headers"]:
+ if header["name"] == "Subject":
+ subject = header["value"]
+ break
+ if subject: # skip if no Subject line
+ print(f"- {subject}, {nmsgs}")
+ return threads
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ show_chatty_threads()
# [END gmail_show_chatty_threads]
diff --git a/gmail/snippet/threads.py b/gmail/snippet/threads.py
deleted file mode 100644
index fb20da43..00000000
--- a/gmail/snippet/threads.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""Functions for using threads with the Gmail API
-"""
-
-from __future__ import print_function
-
-
-# [START show_chatty_threads]
-def show_chatty_threads(service, user_id='me'):
- threads = service.users().threads().list(userId=user_id).execute().get('threads', [])
- for thread in threads:
- tdata = service.users().threads().get(userId=user_id, id=thread['id']).execute()
- nmsgs = len(tdata['messages'])
-
- if nmsgs > 2: # skip if <3 msgs in thread
- msg = tdata['messages'][0]['payload']
- subject = ''
- for header in msg['headers']:
- if header['name'] == 'Subject':
- subject = header['value']
- break
- if subject: # skip if no Subject line
- print('- %s (%d msgs)' % (subject, nmsgs))
-# [END show_chatty_threads]
diff --git a/meet/README.md b/meet/README.md
new file mode 100644
index 00000000..588c40a2
--- /dev/null
+++ b/meet/README.md
@@ -0,0 +1 @@
+Additional samples can be found at https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-meet
\ No newline at end of file
diff --git a/drive/activity/quickstart.py b/meet/quickstart/quickstart.py
similarity index 57%
rename from drive/activity/quickstart.py
rename to meet/quickstart/quickstart.py
index 8f31c5de..077f91d4 100644
--- a/drive/activity/quickstart.py
+++ b/meet/quickstart/quickstart.py
@@ -12,24 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# [START drive_activity_quickstart]
+# [START meet_quickstart]
from __future__ import print_function
-import datetime
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
-from googleapiclient.discovery import build
+from google.apps import meet_v2
+
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/activity']
+SCOPES = ['https://www.googleapis.com/auth/meetings.space.created']
def main():
- """Shows basic usage of the Drive Activity API.
- Prints information about the last 10 events that occured the user's Drive.
+ """Shows basic usage of the Google Meet API.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
@@ -49,29 +48,16 @@ def main():
with open('token.json', 'w') as token:
token.write(creds.to_json())
- service = build('appsactivity', 'v1', credentials=creds)
-
- # Call the Drive Activity API
- results = service.activities().list(source='drive.google.com',
- drive_ancestorId='root', pageSize=10).execute()
- activities = results.get('activities', [])
-
- if not activities:
- print('No activity.')
- else:
- print('Recent activity:')
- for activity in activities:
- event = activity['combinedEvent']
- user = event.get('user', None)
- target = event.get('target', None)
- if user is None or target is None:
- continue
- time = datetime.datetime.fromtimestamp(
- int(event['eventTimeMillis']) / 1000)
- print(u'{0}: {1}, {2}, {3} ({4})'.format(time, user['name'],
- event['primaryEventType'], target['name'], target['mimeType']))
+ try:
+ client = meet_v2.SpacesServiceClient(credentials=creds)
+ request = meet_v2.CreateSpaceRequest()
+ response = client.create_space(request=request)
+ print(f'Space created: {response.meeting_uri}')
+ except Exception as error:
+ # TODO(developer) - Handle errors from Meet API.
+ print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
-# [END drive_activity_quickstart]
+# [END meet_quickstart]
diff --git a/meet/quickstart/requirements.txt b/meet/quickstart/requirements.txt
new file mode 100644
index 00000000..7eee1e6d
--- /dev/null
+++ b/meet/quickstart/requirements.txt
@@ -0,0 +1,3 @@
+google-apps-meet==0.1.6
+google-auth-httplib2==0.1.0
+google-auth-oauthlib==0.4.0
\ No newline at end of file
diff --git a/people/quickstart/quickstart.py b/people/quickstart/quickstart.py
index 65a07282..3129e453 100644
--- a/people/quickstart/quickstart.py
+++ b/people/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START people_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,51 +22,58 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/contacts.readonly']
+SCOPES = ["https://www.googleapis.com/auth/contacts.readonly"]
def main():
- """Shows basic usage of the People API.
- Prints the name of the first 10 connections.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the People API.
+ Prints the name of the first 10 connections.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('people', 'v1', credentials=creds)
+ try:
+ service = build("people", "v1", credentials=creds)
- # Call the People API
- print('List 10 connection names')
- results = service.people().connections().list(
- resourceName='people/me',
+ # Call the People API
+ print("List 10 connection names")
+ results = (
+ service.people()
+ .connections()
+ .list(
+ resourceName="people/me",
pageSize=10,
- personFields='names,emailAddresses').execute()
- connections = results.get('connections', [])
+ personFields="names,emailAddresses",
+ )
+ .execute()
+ )
+ connections = results.get("connections", [])
- for person in connections:
- names = person.get('names', [])
- if names:
- name = names[0].get('displayName')
- print(name)
- except HttpError as err:
- print(err)
+ for person in connections:
+ names = person.get("names", [])
+ if names:
+ name = names[0].get("displayName")
+ print(name)
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END people_quickstart]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..eaaa7420
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,5 @@
+[tool.pyink]
+line-length = 80
+preview = true
+pyink-indentation = 2
+pyink-use-majority-quotes = true
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
deleted file mode 100644
index f45d8f11..00000000
--- a/renovate.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extends": [
- "config:base"
- ]
-}
diff --git a/sheets/quickstart/quickstart.py b/sheets/quickstart/quickstart.py
index 236ab878..6cb90a21 100644
--- a/sheets/quickstart/quickstart.py
+++ b/sheets/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START sheets_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,56 +22,60 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']
+SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
# The ID and range of a sample spreadsheet.
-SAMPLE_SPREADSHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'
-SAMPLE_RANGE_NAME = 'Class Data!A2:E'
+SAMPLE_SPREADSHEET_ID = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
+SAMPLE_RANGE_NAME = "Class Data!A2:E"
def main():
- """Shows basic usage of the Sheets API.
- Prints values from a sample spreadsheet.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Sheets API.
+ Prints values from a sample spreadsheet.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('sheets', 'v4', credentials=creds)
+ try:
+ service = build("sheets", "v4", credentials=creds)
- # Call the Sheets API
- sheet = service.spreadsheets()
- result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
- range=SAMPLE_RANGE_NAME).execute()
- values = result.get('values', [])
+ # Call the Sheets API
+ sheet = service.spreadsheets()
+ result = (
+ sheet.values()
+ .get(spreadsheetId=SAMPLE_SPREADSHEET_ID, range=SAMPLE_RANGE_NAME)
+ .execute()
+ )
+ values = result.get("values", [])
- if not values:
- print('No data found.')
- return
+ if not values:
+ print("No data found.")
+ return
- print('Name, Major:')
- for row in values:
- # Print columns A and E, which correspond to indices 0 and 4.
- print('%s, %s' % (row[0], row[4]))
- except HttpError as err:
- print(err)
+ print("Name, Major:")
+ for row in values:
+ # Print columns A and E, which correspond to indices 0 and 4.
+ print(f"{row[0]}, {row[4]}")
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END sheets_quickstart]
diff --git a/sheets/snippets/base_test.py b/sheets/snippets/base_test.py
index 4f189163..56ea3116 100644
--- a/sheets/snippets/base_test.py
+++ b/sheets/snippets/base_test.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import print_function
-
import sys
import unittest
@@ -24,75 +22,74 @@
class BaseTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.credentials = cls.create_credentials()
- http = cls.credentials.authorize(httplib2.Http())
- cls.credentials.refresh(http)
- cls.service = build('sheets', 'v4', http=http)
- cls.drive_service = build('drive', 'v3', http=http)
- # Hide STDOUT output generated by snippets.
- cls.stdout = sys.stdout
- sys.stdout = None
- @classmethod
- def tearDownClass(cls):
- # Restore STDOUT.
- sys.stdout = cls.stdout
+ @classmethod
+ def setUpClass(cls):
+ cls.credentials = cls.create_credentials()
+ http = cls.credentials.authorize(httplib2.Http())
+ cls.credentials.refresh(http)
+ cls.service = build("sheets", "v4", http=http)
+ cls.drive_service = build("drive", "v3", http=http)
+ # Hide STDOUT output generated by snippets.
+ cls.stdout = sys.stdout
+ sys.stdout = None
- @classmethod
- def create_credentials(cls):
- cls.credentials = GoogleCredentials.get_application_default()
- scope = ['https://www.googleapis.com/auth/drive']
- return cls.credentials.create_scoped(scope)
+ @classmethod
+ def tearDownClass(cls):
+ # Restore STDOUT.
+ sys.stdout = cls.stdout
- def setUp(self):
- self.files_to_delete = []
+ @classmethod
+ def create_credentials(cls):
+ cls.credentials = GoogleCredentials.get_application_default()
+ scope = ["https://www.googleapis.com/auth/drive"]
+ return cls.credentials.create_scoped(scope)
- def tearDown(self):
- for file_id in self.files_to_delete:
- try:
- self.drive_service.files().delete(fileId=file_id).execute()
- except errors.HttpError:
- print('Unable to delete file %s' % file_id, file=sys.stderr)
+ def setUp(self):
+ self.files_to_delete = []
- def delete_file_on_cleanup(self, file_id):
- self.files_to_delete.append(file_id)
+ def tearDown(self):
+ for file_id in self.files_to_delete:
+ try:
+ self.drive_service.files().delete(fileId=file_id).execute()
+ except errors.HttpError:
+ print(f"Unable to delete file {file_id}", file=sys.stderr)
- def create_test_spreadsheet(self):
- spreadsheet = {
- 'properties': {
- 'title': 'Sales Report'
- }
- }
- spreadsheet = self.service.spreadsheets().create(body=spreadsheet,
- fields='spreadsheetId').execute()
- self.delete_file_on_cleanup(spreadsheet.get('spreadsheetId'))
- return spreadsheet.get('spreadsheetId')
+ def delete_file_on_cleanup(self, file_id):
+ self.files_to_delete.append(file_id)
- def populate_values(self, spreadsheet_id):
- body = {
- 'requests': [{
- 'repeatCell': {
- 'range': {
- 'sheetId': 0,
- 'startRowIndex': 0,
- 'endRowIndex': 10,
- 'startColumnIndex': 0,
- 'endColumnIndex': 10
- },
- 'cell': {
- 'userEnteredValue': {
- 'stringValue': 'Hello'
- }
+ def create_test_spreadsheet(self):
+ spreadsheet = {"properties": {"title": "Sales Report"}}
+ spreadsheet = (
+ self.service.spreadsheets()
+ .create(body=spreadsheet, fields="spreadsheetId")
+ .execute()
+ )
+ self.delete_file_on_cleanup(spreadsheet.get("spreadsheetId"))
+ return spreadsheet.get("spreadsheetId")
+
+ def populate_values(self, spreadsheet_id):
+ body = {
+ "requests": [
+ {
+ "repeatCell": {
+ "range": {
+ "sheetId": 0,
+ "startRowIndex": 0,
+ "endRowIndex": 10,
+ "startColumnIndex": 0,
+ "endColumnIndex": 10,
},
- 'fields': 'userEnteredValue'
+ "cell": {"userEnteredValue": {"stringValue": "Hello"}},
+ "fields": "userEnteredValue",
}
- }]
- }
- self.service.spreadsheets().batchUpdate(
- spreadsheetId=spreadsheet_id, body=body).execute()
+ }
+ ]
+ }
+ self.service.spreadsheets().batchUpdate(
+ spreadsheetId=spreadsheet_id, body=body
+ ).execute()
-if __name__ == '__main__':
- unittest.main()
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/sheets_append_values.py b/sheets/snippets/sheets_append_values.py
new file mode 100644
index 00000000..3fba74f5
--- /dev/null
+++ b/sheets/snippets/sheets_append_values.py
@@ -0,0 +1,72 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_append_values]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def append_values(spreadsheet_id, range_name, value_input_option, _values):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ values = [
+ [
+ # Cell values ...
+ ],
+ # Additional rows ...
+ ]
+ # [START_EXCLUDE silent]
+ values = _values
+ # [END_EXCLUDE]
+ body = {"values": values}
+ result = (
+ service.spreadsheets()
+ .values()
+ .append(
+ spreadsheetId=spreadsheet_id,
+ range=range_name,
+ valueInputOption=value_input_option,
+ body=body,
+ )
+ .execute()
+ )
+ print(f"{(result.get('updates').get('updatedCells'))} cells appended.")
+ return result
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id, range_name value_input_option and _values)
+ append_values(
+ "1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k",
+ "A1:C2",
+ "USER_ENTERED",
+ [["F", "B"], ["C", "D"]],
+ )
+ # [END sheets_append_values]
diff --git a/sheets/snippets/sheets_batch_get_values.py b/sheets/snippets/sheets_batch_get_values.py
new file mode 100644
index 00000000..65666839
--- /dev/null
+++ b/sheets/snippets/sheets_batch_get_values.py
@@ -0,0 +1,58 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_batch_get_values]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def batch_get_values(spreadsheet_id, _range_names):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+ range_names = [
+ # Range names ...
+ ]
+ # [START_EXCLUDE silent]
+ range_names = _range_names
+ # [END_EXCLUDE]
+ result = (
+ service.spreadsheets()
+ .values()
+ .batchGet(spreadsheetId=spreadsheet_id, ranges=range_names)
+ .execute()
+ )
+ ranges = result.get("valueRanges", [])
+ print(f"{len(ranges)} ranges retrieved")
+ return result
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id, and range_name
+
+ batch_get_values("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k", "A1:C2")
+ # [END sheets_batch_get_values]
diff --git a/sheets/snippets/sheets_batch_update.py b/sheets/snippets/sheets_batch_update.py
new file mode 100644
index 00000000..037db84c
--- /dev/null
+++ b/sheets/snippets/sheets_batch_update.py
@@ -0,0 +1,79 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_batch_update]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def sheets_batch_update(spreadsheet_id, title, find, replacement):
+ """
+ Update the sheet details in batch, the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ requests = []
+ # Change the spreadsheet's title.
+ requests.append(
+ {
+ "updateSpreadsheetProperties": {
+ "properties": {"title": title},
+ "fields": "title",
+ }
+ }
+ )
+ # Find and replace text
+ requests.append(
+ {
+ "findReplace": {
+ "find": find,
+ "replacement": replacement,
+ "allSheets": True,
+ }
+ }
+ )
+ # Add additional requests (operations) ...
+
+ body = {"requests": requests}
+ response = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ find_replace_response = response.get("replies")[1].get("findReplace")
+ print(
+ f"{find_replace_response.get('occurrencesChanged')} replacements made."
+ )
+ return response
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ sheets_batch_update("spreadsheet_id", "title", "find", "replacement")
+
+# [END sheets_batch_update]
diff --git a/sheets/snippets/sheets_batch_update_values.py b/sheets/snippets/sheets_batch_update_values.py
new file mode 100644
index 00000000..c125ccbd
--- /dev/null
+++ b/sheets/snippets/sheets_batch_update_values.py
@@ -0,0 +1,72 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_batch_update_values]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def batch_update_values(
+ spreadsheet_id, range_name, value_input_option, _values
+):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ values = [
+ [
+ # Cell values ...
+ ],
+ # Additional rows
+ ]
+ # [START_EXCLUDE silent]
+ values = _values
+ # [END_EXCLUDE]
+ data = [
+ {"range": range_name, "values": values},
+ # Additional ranges to update ...
+ ]
+ body = {"valueInputOption": value_input_option, "data": data}
+ result = (
+ service.spreadsheets()
+ .values()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ print(f"{(result.get('totalUpdatedCells'))} cells updated.")
+ return result
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id, range_name value_input_option and _values)
+ batch_update_values(
+ "1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k",
+ "A1:C2",
+ "USER_ENTERED",
+ [["F", "B"], ["C", "D"]],
+ )
+ # [END sheets_batch_update_values]
diff --git a/sheets/snippets/sheets_conditional_formatting.py b/sheets/snippets/sheets_conditional_formatting.py
new file mode 100644
index 00000000..d8951f1d
--- /dev/null
+++ b/sheets/snippets/sheets_conditional_formatting.py
@@ -0,0 +1,111 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_conditional_formatting]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def conditional_formatting(spreadsheet_id):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ my_range = {
+ "sheetId": 0,
+ "startRowIndex": 1,
+ "endRowIndex": 11,
+ "startColumnIndex": 0,
+ "endColumnIndex": 4,
+ }
+ requests = [
+ {
+ "addConditionalFormatRule": {
+ "rule": {
+ "ranges": [my_range],
+ "booleanRule": {
+ "condition": {
+ "type": "CUSTOM_FORMULA",
+ "values": [
+ {
+ "userEnteredValue": (
+ "=GT($D2,median($D$2:$D$11))"
+ )
+ }
+ ],
+ },
+ "format": {
+ "textFormat": {"foregroundColor": {"red": 0.8}}
+ },
+ },
+ },
+ "index": 0,
+ }
+ },
+ {
+ "addConditionalFormatRule": {
+ "rule": {
+ "ranges": [my_range],
+ "booleanRule": {
+ "condition": {
+ "type": "CUSTOM_FORMULA",
+ "values": [
+ {
+ "userEnteredValue": (
+ "=LT($D2,median($D$2:$D$11))"
+ )
+ }
+ ],
+ },
+ "format": {
+ "backgroundColor": {
+ "red": 1,
+ "green": 0.4,
+ "blue": 0.4,
+ }
+ },
+ },
+ },
+ "index": 0,
+ }
+ },
+ ]
+ body = {"requests": requests}
+ response = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ print(f"{(len(response.get('replies')))} cells updated.")
+ return response
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id
+ conditional_formatting("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k")
+ # [END sheets_conditional_formatting]
diff --git a/sheets/snippets/sheets_create.py b/sheets/snippets/sheets_create.py
new file mode 100644
index 00000000..20585f12
--- /dev/null
+++ b/sheets/snippets/sheets_create.py
@@ -0,0 +1,50 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_create]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create(title):
+ """
+ Creates the Sheet the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+ spreadsheet = {"properties": {"title": title}}
+ spreadsheet = (
+ service.spreadsheets()
+ .create(body=spreadsheet, fields="spreadsheetId")
+ .execute()
+ )
+ print(f"Spreadsheet ID: {(spreadsheet.get('spreadsheetId'))}")
+ return spreadsheet.get("spreadsheetId")
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: title
+ create("mysheet1")
+ # [END sheets_create]
diff --git a/sheets/snippets/sheets_filter_views.py b/sheets/snippets/sheets_filter_views.py
new file mode 100644
index 00000000..d7514aee
--- /dev/null
+++ b/sheets/snippets/sheets_filter_views.py
@@ -0,0 +1,119 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_filter_views]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def filter_views(spreadsheet_id):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ my_range = {
+ "sheetId": 0,
+ "startRowIndex": 0,
+ "startColumnIndex": 0,
+ }
+ addfilterviewrequest = {
+ "addFilterView": {
+ "filter": {
+ "title": "Sample Filter",
+ "range": my_range,
+ "sortSpecs": [{
+ "dimensionIndex": 3,
+ "sortOrder": "DESCENDING",
+ }],
+ "criteria": {
+ 0: {"hiddenValues": ["Panel"]},
+ 6: {
+ "condition": {
+ "type": "DATE_BEFORE",
+ "values": {"userEnteredValue": "4/30/2016"},
+ }
+ },
+ },
+ }
+ }
+ }
+
+ body = {"requests": [addfilterviewrequest]}
+ addfilterviewresponse = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+
+ duplicatefilterviewrequest = {
+ "duplicateFilterView": {
+ "filterId": addfilterviewresponse["replies"][0]["addFilterView"][
+ "filter"
+ ]["filterViewId"]
+ }
+ }
+
+ body = {"requests": [duplicatefilterviewrequest]}
+ duplicatefilterviewresponse = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+
+ updatefilterviewrequest = {
+ "updateFilterView": {
+ "filter": {
+ "filterViewId": duplicatefilterviewresponse["replies"][0][
+ "duplicateFilterView"
+ ]["filter"]["filterViewId"],
+ "title": "Updated Filter",
+ "criteria": {
+ 0: {},
+ 3: {
+ "condition": {
+ "type": "NUMBER_GREATER",
+ "values": {"userEnteredValue": "5"},
+ }
+ },
+ },
+ },
+ "fields": {"paths": ["criteria", "title"]},
+ }
+ }
+
+ body = {"requests": [updatefilterviewrequest]}
+ updatefilterviewresponse = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ print(str(updatefilterviewresponse))
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id
+ filter_views("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k")
+ # [END sheets_filter_views]
diff --git a/sheets/snippets/sheets_get_values.py b/sheets/snippets/sheets_get_values.py
new file mode 100644
index 00000000..d0d46d6a
--- /dev/null
+++ b/sheets/snippets/sheets_get_values.py
@@ -0,0 +1,52 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_get_values]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def get_values(spreadsheet_id, range_name):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+
+ result = (
+ service.spreadsheets()
+ .values()
+ .get(spreadsheetId=spreadsheet_id, range=range_name)
+ .execute()
+ )
+ rows = result.get("values", [])
+ print(f"{len(rows)} rows retrieved")
+ return result
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id, and range_name
+ get_values("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k", "A1:C2")
+ # [END sheets_get_values]
diff --git a/sheets/snippets/sheets_pivot_tables.py b/sheets/snippets/sheets_pivot_tables.py
new file mode 100644
index 00000000..86524c32
--- /dev/null
+++ b/sheets/snippets/sheets_pivot_tables.py
@@ -0,0 +1,114 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_pivot_tables]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def pivot_tables(spreadsheet_id):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+ # Create two sheets for our pivot table.
+ body = {"requests": [{"addSheet": {}}, {"addSheet": {}}]}
+ batch_update_response = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ source_sheet_id = (
+ batch_update_response.get("replies")[0]
+ .get("addSheet")
+ .get("properties")
+ .get("sheetId")
+ )
+ target_sheet_id = (
+ batch_update_response.get("replies")[1]
+ .get("addSheet")
+ .get("properties")
+ .get("sheetId")
+ )
+ requests = []
+ requests.append(
+ {
+ "updateCells": {
+ "rows": {
+ "values": [
+ {
+ "pivotTable": {
+ "source": {
+ "sheetId": source_sheet_id,
+ "startRowIndex": 0,
+ "startColumnIndex": 0,
+ "endRowIndex": 20,
+ "endColumnIndex": 7,
+ },
+ "rows": [
+ {
+ "sourceColumnOffset": 1,
+ "showTotals": True,
+ "sortOrder": "ASCENDING",
+ },
+ ],
+ "columns": [{
+ "sourceColumnOffset": 4,
+ "sortOrder": "ASCENDING",
+ "showTotals": True,
+ }],
+ "values": [{
+ "summarizeFunction": "COUNTA",
+ "sourceColumnOffset": 4,
+ }],
+ "valueLayout": "HORIZONTAL",
+ }
+ }
+ ]
+ },
+ "start": {
+ "sheetId": target_sheet_id,
+ "rowIndex": 0,
+ "columnIndex": 0,
+ },
+ "fields": "pivotTable",
+ }
+ }
+ )
+ body = {"requests": requests}
+ response = (
+ service.spreadsheets()
+ .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
+ .execute()
+ )
+ return response
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id
+ pivot_tables("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k")
+ # [END sheets_pivot_tables]
diff --git a/sheets/snippets/sheets_update_values.py b/sheets/snippets/sheets_update_values.py
new file mode 100644
index 00000000..962b8cc3
--- /dev/null
+++ b/sheets/snippets/sheets_update_values.py
@@ -0,0 +1,70 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START sheets_update_values]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def update_values(spreadsheet_id, range_name, value_input_option, _values):
+ """
+ Creates the batch_update the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("sheets", "v4", credentials=creds)
+ values = [
+ [
+ # Cell values ...
+ ],
+ # Additional rows ...
+ ]
+ # [START_EXCLUDE silent]
+ values = _values
+ # [END_EXCLUDE]
+ body = {"values": values}
+ result = (
+ service.spreadsheets()
+ .values()
+ .update(
+ spreadsheetId=spreadsheet_id,
+ range=range_name,
+ valueInputOption=value_input_option,
+ body=body,
+ )
+ .execute()
+ )
+ print(f"{result.get('updatedCells')} cells updated.")
+ return result
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Pass: spreadsheet_id, range_name, value_input_option and _values
+ update_values(
+ "1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k",
+ "A1:C2",
+ "USER_ENTERED",
+ [["A", "B"], ["C", "D"]],
+ )
+ # [END sheets_update_values]
diff --git a/sheets/snippets/spreadsheet_snippets.py b/sheets/snippets/spreadsheet_snippets.py
deleted file mode 100644
index bef2d5f4..00000000
--- a/sheets/snippets/spreadsheet_snippets.py
+++ /dev/null
@@ -1,394 +0,0 @@
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-
-class SpreadsheetSnippets(object):
- def __init__(self, service):
- self.service = service
-
- def create(self, title):
- service = self.service
- # [START sheets_create]
- spreadsheet = {
- 'properties': {
- 'title': title
- }
- }
- spreadsheet = service.spreadsheets().create(body=spreadsheet,
- fields='spreadsheetId').execute()
- print('Spreadsheet ID: {0}'.format(spreadsheet.get('spreadsheetId')))
- # [END sheets_create]
- return spreadsheet.get('spreadsheetId')
-
- def batch_update(self, spreadsheet_id, title, find, replacement):
- service = self.service
- # [START sheets_batch_update]
- requests = []
- # Change the spreadsheet's title.
- requests.append({
- 'updateSpreadsheetProperties': {
- 'properties': {
- 'title': title
- },
- 'fields': 'title'
- }
- })
- # Find and replace text
- requests.append({
- 'findReplace': {
- 'find': find,
- 'replacement': replacement,
- 'allSheets': True
- }
- })
- # Add additional requests (operations) ...
-
- body = {
- 'requests': requests
- }
- response = service.spreadsheets().batchUpdate(
- spreadsheetId=spreadsheet_id,
- body=body).execute()
- find_replace_response = response.get('replies')[1].get('findReplace')
- print('{0} replacements made.'.format(
- find_replace_response.get('occurrencesChanged')))
- # [END sheets_batch_update]
- return response
-
- def get_values(self, spreadsheet_id, range_name):
- service = self.service
- # [START sheets_get_values]
- result = service.spreadsheets().values().get(
- spreadsheetId=spreadsheet_id, range=range_name).execute()
- rows = result.get('values', [])
- print('{0} rows retrieved.'.format(len(rows)))
- # [END sheets_get_values]
- return result
-
- def batch_get_values(self, spreadsheet_id, _range_names):
- service = self.service
- # [START sheets_batch_get_values]
- range_names = [
- # Range names ...
- ]
- # [START_EXCLUDE silent]
- range_names = _range_names
- # [END_EXCLUDE]
- result = service.spreadsheets().values().batchGet(
- spreadsheetId=spreadsheet_id, ranges=range_names).execute()
- ranges = result.get('valueRanges', [])
- print('{0} ranges retrieved.'.format(len(ranges)))
- # [END sheets_batch_get_values]
- return result
-
- def update_values(self, spreadsheet_id, range_name, value_input_option,
- _values):
- service = self.service
- # [START sheets_update_values]
- values = [
- [
- # Cell values ...
- ],
- # Additional rows ...
- ]
- # [START_EXCLUDE silent]
- values = _values
- # [END_EXCLUDE]
- body = {
- 'values': values
- }
- result = service.spreadsheets().values().update(
- spreadsheetId=spreadsheet_id, range=range_name,
- valueInputOption=value_input_option, body=body).execute()
- print('{0} cells updated.'.format(result.get('updatedCells')))
- # [END sheets_update_values]
- return result
-
- def batch_update_values(self, spreadsheet_id, range_name,
- value_input_option, _values):
- service = self.service
- # [START sheets_batch_update_values]
- values = [
- [
- # Cell values ...
- ],
- # Additional rows
- ]
- # [START_EXCLUDE silent]
- values = _values
- # [END_EXCLUDE]
- data = [
- {
- 'range': range_name,
- 'values': values
- },
- # Additional ranges to update ...
- ]
- body = {
- 'valueInputOption': value_input_option,
- 'data': data
- }
- result = service.spreadsheets().values().batchUpdate(
- spreadsheetId=spreadsheet_id, body=body).execute()
- print('{0} cells updated.'.format(result.get('totalUpdatedCells')))
- # [END sheets_batch_update_values]
- return result
-
- def append_values(self, spreadsheet_id, range_name, value_input_option,
- _values):
- service = self.service
- # [START sheets_append_values]
- values = [
- [
- # Cell values ...
- ],
- # Additional rows ...
- ]
- # [START_EXCLUDE silent]
- values = _values
- # [END_EXCLUDE]
- body = {
- 'values': values
- }
- result = service.spreadsheets().values().append(
- spreadsheetId=spreadsheet_id, range=range_name,
- valueInputOption=value_input_option, body=body).execute()
- print('{0} cells appended.'.format(result
- .get('updates')
- .get('updatedCells')))
- # [END sheets_append_values]
- return result
-
- def pivot_tables(self, spreadsheet_id):
- service = self.service
- # Create two sheets for our pivot table.
- body = {
- 'requests': [{
- 'addSheet': {}
- }, {
- 'addSheet': {}
- }]
- }
- batch_update_response = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
- source_sheet_id = batch_update_response.get('replies')[0] \
- .get('addSheet').get('properties').get('sheetId')
- target_sheet_id = batch_update_response.get('replies')[1] \
- .get('addSheet').get('properties').get('sheetId')
- requests = []
- # [START sheets_pivot_tables]
- requests.append({
- 'updateCells': {
- 'rows': {
- 'values': [
- {
- 'pivotTable': {
- 'source': {
- 'sheetId': source_sheet_id,
- 'startRowIndex': 0,
- 'startColumnIndex': 0,
- 'endRowIndex': 20,
- 'endColumnIndex': 7
- },
- 'rows': [
- {
- 'sourceColumnOffset': 1,
- 'showTotals': True,
- 'sortOrder': 'ASCENDING',
-
- },
-
- ],
- 'columns': [
- {
- 'sourceColumnOffset': 4,
- 'sortOrder': 'ASCENDING',
- 'showTotals': True,
-
- }
- ],
- 'values': [
- {
- 'summarizeFunction': 'COUNTA',
- 'sourceColumnOffset': 4
- }
- ],
- 'valueLayout': 'HORIZONTAL'
- }
- }
- ]
- },
- 'start': {
- 'sheetId': target_sheet_id,
- 'rowIndex': 0,
- 'columnIndex': 0
- },
- 'fields': 'pivotTable'
- }
- })
- body = {
- 'requests': requests
- }
- response = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
- # [END sheets_pivot_tables]
- return response
-
- def conditional_formatting(self, spreadsheet_id):
- service = self.service
-
- # [START sheets_conditional_formatting]
- my_range = {
- 'sheetId': 0,
- 'startRowIndex': 1,
- 'endRowIndex': 11,
- 'startColumnIndex': 0,
- 'endColumnIndex': 4,
- }
- requests = [{
- 'addConditionalFormatRule': {
- 'rule': {
- 'ranges': [my_range],
- 'booleanRule': {
- 'condition': {
- 'type': 'CUSTOM_FORMULA',
- 'values': [{
- 'userEnteredValue':
- '=GT($D2,median($D$2:$D$11))'
- }]
- },
- 'format': {
- 'textFormat': {
- 'foregroundColor': {'red': 0.8}
- }
- }
- }
- },
- 'index': 0
- }
- }, {
- 'addConditionalFormatRule': {
- 'rule': {
- 'ranges': [my_range],
- 'booleanRule': {
- 'condition': {
- 'type': 'CUSTOM_FORMULA',
- 'values': [{
- 'userEnteredValue':
- '=LT($D2,median($D$2:$D$11))'
- }]
- },
- 'format': {
- 'backgroundColor': {
- 'red': 1,
- 'green': 0.4,
- 'blue': 0.4
- }
- }
- }
- },
- 'index': 0
- }
- }]
- body = {
- 'requests': requests
- }
- response = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
- print('{0} cells updated.'.format(len(response.get('replies'))))
- # [END sheets_conditional_formatting]
- return response
-
- def filter_views(self, spreadsheet_id):
- service = self.service
-
- # [START sheets_filter_views]
- my_range = {
- 'sheetId': 0,
- 'startRowIndex': 0,
- 'startColumnIndex': 0,
- }
- addFilterViewRequest = {
- 'addFilterView': {
- 'filter': {
- 'title': 'Sample Filter',
- 'range': my_range,
- 'sortSpecs': [{
- 'dimensionIndex': 3,
- 'sortOrder': 'DESCENDING'
- }],
- 'criteria': {
- 0: {
- 'hiddenValues': ['Panel']
- },
- 6: {
- 'condition': {
- 'type': 'DATE_BEFORE',
- 'values': {
- 'userEnteredValue': '4/30/2016'
- }
- }
- }
- }
- }
- }
- }
-
- body = {'requests': [addFilterViewRequest]}
- addFilterViewResponse = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
-
- duplicateFilterViewRequest = {
- 'duplicateFilterView': {
- 'filterId':
- addFilterViewResponse['replies'][0]['addFilterView']['filter']
- ['filterViewId']
- }
- }
-
- body = {'requests': [duplicateFilterViewRequest]}
- duplicateFilterViewResponse = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
-
- updateFilterViewRequest = {
- 'updateFilterView': {
- 'filter': {
- 'filterViewId': duplicateFilterViewResponse['replies'][0]
- ['duplicateFilterView']['filter']['filterViewId'],
- 'title': 'Updated Filter',
- 'criteria': {
- 0: {},
- 3: {
- 'condition': {
- 'type': 'NUMBER_GREATER',
- 'values': {
- 'userEnteredValue': '5'
- }
- }
- }
- }
- },
- 'fields': {
- 'paths': ['criteria', 'title']
- }
- }
- }
-
- body = {'requests': [updateFilterViewRequest]}
- updateFilterViewResponse = service.spreadsheets() \
- .batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
- print(str(updateFilterViewResponse))
- # [END sheets_filter_views]
diff --git a/sheets/snippets/test_sheets_append_values.py b/sheets/snippets/test_sheets_append_values.py
new file mode 100644
index 00000000..1a2257dd
--- /dev/null
+++ b/sheets/snippets/test_sheets_append_values.py
@@ -0,0 +1,40 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_append_values
+from base_test import BaseTest
+
+
+class Testappendvalues(BaseTest):
+ """Unit test for append value Sheet snippet"""
+
+ def test_append_values(self):
+ """test append values function"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ result = sheets_append_values.append_values(
+ spreadsheet_id, "Sheet1", "USER_ENTERED", [["A", "B"], ["C", "D"]]
+ )
+ self.assertIsNotNone(result)
+ self.assertEqual("Sheet1!A1:J10", result.get("tableRange"))
+ updates = result.get("updates")
+ self.assertEqual("Sheet1!A11:B12", updates.get("updatedRange"))
+ self.assertEqual(2, updates.get("updatedRows"))
+ self.assertEqual(2, updates.get("updatedColumns"))
+ self.assertEqual(4, updates.get("updatedCells"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_batch_get_values.py b/sheets/snippets/test_sheets_batch_get_values.py
new file mode 100644
index 00000000..cd87729f
--- /dev/null
+++ b/sheets/snippets/test_sheets_batch_get_values.py
@@ -0,0 +1,39 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_batch_get_values
+from base_test import BaseTest
+
+
+class Testgetvalues(BaseTest):
+ """Unit test class for get value Sheet snippet"""
+
+ def test_batch_get_values(self):
+ """test batch get values function"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ result = sheets_batch_get_values.batch_get_values(
+ spreadsheet_id, ["A1:A3", "B1:C1"]
+ )
+ self.assertIsNotNone(result)
+ valueranges = result.get("valueRanges")
+ self.assertIsNotNone(valueranges)
+ self.assertEqual(2, len(valueranges))
+ values = valueranges[0].get("values")
+ self.assertEqual(3, len(values))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_batch_update.py b/sheets/snippets/test_sheets_batch_update.py
new file mode 100644
index 00000000..e371e5da
--- /dev/null
+++ b/sheets/snippets/test_sheets_batch_update.py
@@ -0,0 +1,41 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_batch_update
+import sheets_create
+from base_test import BaseTest
+
+
+class Testbatchupdate(BaseTest):
+ """Unit test class for Batch update Sheet snippet"""
+
+ def test_batch_update(self):
+ """test_batch_update function"""
+ spreadsheet_id = sheets_create.create("Title")
+ self.populate_values(spreadsheet_id)
+ response = sheets_batch_update.sheets_batch_update(
+ spreadsheet_id, "New Title", "Hello", "Goodbye"
+ )
+ self.assertIsNotNone(response)
+ replies = response.get("replies")
+ self.assertIsNotNone(replies)
+ self.assertEqual(2, len(replies))
+ find_replace_response = replies[1].get("findReplace")
+ self.assertIsNotNone(find_replace_response)
+ self.assertEqual(100, find_replace_response.get("occurrencesChanged"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_batch_update_values.py b/sheets/snippets/test_sheets_batch_update_values.py
new file mode 100644
index 00000000..c594a0a8
--- /dev/null
+++ b/sheets/snippets/test_sheets_batch_update_values.py
@@ -0,0 +1,37 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_batch_update_values
+from base_test import BaseTest
+
+
+class Testbatchupdatevalues(BaseTest):
+ """Unit test for Batch update value Sheet snippet"""
+
+ def test_batch_update_values(self):
+ """batch updates values"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ result = sheets_batch_update_values.batch_update_values(
+ spreadsheet_id, "A1:B2", "USER_ENTERED", [["A", "B"], ["C", "D"]]
+ )
+ self.assertIsNotNone(result)
+ self.assertEqual(1, len(result.get("responses")))
+ self.assertEqual(2, result.get("totalUpdatedRows"))
+ self.assertEqual(2, result.get("totalUpdatedColumns"))
+ self.assertEqual(4, result.get("totalUpdatedCells"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_conditional_formatting.py b/sheets/snippets/test_sheets_conditional_formatting.py
new file mode 100644
index 00000000..2bf78657
--- /dev/null
+++ b/sheets/snippets/test_sheets_conditional_formatting.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_conditional_formatting
+from base_test import BaseTest
+
+
+class Testconditionalformatting(BaseTest):
+ """Unit test for sheets conditional_formatting value Sheet snippet"""
+
+ def test_conditional_formatting(self):
+ """sheets_conditional_formatting function"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ response = sheets_conditional_formatting.conditional_formatting(
+ spreadsheet_id
+ )
+ self.assertEqual(2, len(response.get("replies")))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_create.py b/sheets/snippets/test_sheets_create.py
new file mode 100644
index 00000000..3ac529e5
--- /dev/null
+++ b/sheets/snippets/test_sheets_create.py
@@ -0,0 +1,31 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_create
+from base_test import BaseTest
+
+
+class Testsheetscreate(BaseTest):
+ """Unit test class for Create Sheet snippet"""
+
+ def test_create(self):
+ """sheet function for Create sheet"""
+ spreadsheet_id = sheets_create.create("Title")
+ self.assertIsNotNone(spreadsheet_id)
+ self.delete_file_on_cleanup(spreadsheet_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_filter_views.py b/sheets/snippets/test_sheets_filter_views.py
new file mode 100644
index 00000000..6ccc1d71
--- /dev/null
+++ b/sheets/snippets/test_sheets_filter_views.py
@@ -0,0 +1,31 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_filter_views
+from base_test import BaseTest
+
+
+class Testfilterviews(BaseTest):
+ """Unit test for sheets conditional_formatting value Sheet snippet"""
+
+ def test_filter_views(self):
+ """test filter view function"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ sheets_filter_views.filter_views(spreadsheet_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_get_values.py b/sheets/snippets/test_sheets_get_values.py
new file mode 100644
index 00000000..912914e6
--- /dev/null
+++ b/sheets/snippets/test_sheets_get_values.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_get_values
+from base_test import BaseTest
+
+
+class Testgetvalues(BaseTest):
+ """Unit test class for get value Sheet snippet"""
+
+ def test_get_values(self):
+ """test_get_values"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ result = sheets_get_values.get_values(spreadsheet_id, "A1:C2")
+ self.assertIsNotNone(result)
+ values = result.get("values")
+ self.assertIsNotNone(values)
+ self.assertEqual(2, len(values))
+ self.assertEqual(3, len(values[0]))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_pivot_tables.py b/sheets/snippets/test_sheets_pivot_tables.py
new file mode 100644
index 00000000..42acc343
--- /dev/null
+++ b/sheets/snippets/test_sheets_pivot_tables.py
@@ -0,0 +1,32 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_pivot_tables
+from base_test import BaseTest
+
+
+class Testpivottables(BaseTest):
+ """Unit test for Pivot tables value Sheet snippet"""
+
+ def test_pivot_tables(self):
+ """pivot table function"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ self.populate_values(spreadsheet_id)
+ response = sheets_pivot_tables.pivot_tables(spreadsheet_id)
+ self.assertIsNotNone(response)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_sheets_update_values.py b/sheets/snippets/test_sheets_update_values.py
new file mode 100644
index 00000000..2367ae3a
--- /dev/null
+++ b/sheets/snippets/test_sheets_update_values.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import sheets_update_values
+from base_test import BaseTest
+
+
+class Testupdatesvalues(BaseTest):
+ """Unit test for update value Sheet snippet"""
+
+ def test_update_values(self):
+ """test updates_values"""
+ spreadsheet_id = self.create_test_spreadsheet()
+ result = sheets_update_values.update_values(
+ spreadsheet_id, "A1:B2", "USER_ENTERED", [["A", "B"], ["C", "D"]]
+ )
+ self.assertIsNotNone(result)
+ self.assertEqual(2, result.get("updatedRows"))
+ self.assertEqual(2, result.get("updatedColumns"))
+ self.assertEqual(4, result.get("updatedCells"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sheets/snippets/test_spreadsheet_snippets.py b/sheets/snippets/test_spreadsheet_snippets.py
deleted file mode 100644
index fe8da01a..00000000
--- a/sheets/snippets/test_spreadsheet_snippets.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from base_test import BaseTest
-from spreadsheet_snippets import SpreadsheetSnippets
-
-
-class SpreadsheetSnippetsTest(BaseTest):
- @classmethod
- def setUpClass(cls):
- super(SpreadsheetSnippetsTest, cls).setUpClass()
- cls.snippets = SpreadsheetSnippets(cls.service)
-
- def test_create(self):
- spreadsheet_id = self.snippets.create('Title')
- self.assertIsNotNone(spreadsheet_id)
- self.delete_file_on_cleanup(spreadsheet_id)
-
- def test_batch_update(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- response = self.snippets.batch_update(spreadsheet_id,
- 'New Title', 'Hello', 'Goodbye')
- self.assertIsNotNone(response)
- replies = response.get('replies')
- self.assertIsNotNone(replies)
- self.assertEqual(2, len(replies))
- find_replace_response = replies[1].get('findReplace')
- self.assertIsNotNone(find_replace_response)
- self.assertEqual(100, find_replace_response.get('occurrencesChanged'))
-
- def test_get_values(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- result = self.snippets.get_values(spreadsheet_id, 'A1:C2')
- self.assertIsNotNone(result)
- values = result.get('values')
- self.assertIsNotNone(values)
- self.assertEqual(2, len(values))
- self.assertEqual(3, len(values[0]))
-
- def test_batch_get_values(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- result = self.snippets.batch_get_values(spreadsheet_id,
- ['A1:A3', 'B1:C1'])
- self.assertIsNotNone(result)
- valueRanges = result.get('valueRanges')
- self.assertIsNotNone(valueRanges)
- self.assertEqual(2, len(valueRanges))
- values = valueRanges[0].get('values')
- self.assertEqual(3, len(values))
-
- def test_update_values(self):
- spreadsheet_id = self.create_test_spreadsheet()
- result = self.snippets.update_values(spreadsheet_id,
- 'A1:B2', 'USER_ENTERED', [
- ['A', 'B'],
- ['C', 'D']
- ])
- self.assertIsNotNone(result)
- self.assertEqual(2, result.get('updatedRows'))
- self.assertEqual(2, result.get('updatedColumns'))
- self.assertEqual(4, result.get('updatedCells'))
-
- def test_batch_update_values(self):
- spreadsheet_id = self.create_test_spreadsheet()
- result = self.snippets.batch_update_values(spreadsheet_id,
- 'A1:B2', 'USER_ENTERED', [
- ['A', 'B'],
- ['C', 'D']
- ])
- self.assertIsNotNone(result)
- self.assertEqual(1, len(result.get('responses')))
- self.assertEqual(2, result.get('totalUpdatedRows'))
- self.assertEqual(2, result.get('totalUpdatedColumns'))
- self.assertEqual(4, result.get('totalUpdatedCells'))
-
- def test_append_values(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- result = self.snippets.append_values(spreadsheet_id,
- 'Sheet1', 'USER_ENTERED', [
- ['A', 'B'],
- ['C', 'D']
- ])
- self.assertIsNotNone(result)
- self.assertEqual('Sheet1!A1:J10', result.get('tableRange'))
- updates = result.get('updates')
- self.assertEqual('Sheet1!A11:B12', updates.get('updatedRange'))
- self.assertEqual(2, updates.get('updatedRows'))
- self.assertEqual(2, updates.get('updatedColumns'))
- self.assertEqual(4, updates.get('updatedCells'))
-
- def test_pivot_tables(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- response = self.snippets.pivot_tables(spreadsheet_id)
- self.assertIsNotNone(response)
-
- def test_conditional_formatting(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- response = self.snippets.conditional_formatting(spreadsheet_id)
- self.assertEqual(2, len(response.get('replies')))
-
- def test_filter_views(self):
- spreadsheet_id = self.create_test_spreadsheet()
- self.populate_values(spreadsheet_id)
- self.snippets.filter_views(spreadsheet_id)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/slides/quickstart/quickstart.py b/slides/quickstart/quickstart.py
index 6a0ff8e7..f7c17aa3 100644
--- a/slides/quickstart/quickstart.py
+++ b/slides/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START slides_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,50 +22,54 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/presentations.readonly']
+SCOPES = ["https://www.googleapis.com/auth/presentations.readonly"]
# The ID of a sample presentation.
-PRESENTATION_ID = '1EAYk18WDjIG-zp_0vLm3CsfQh_i8eXc67Jo2O9C6Vuc'
+PRESENTATION_ID = "1EAYk18WDjIG-zp_0vLm3CsfQh_i8eXc67Jo2O9C6Vuc"
def main():
- """Shows basic usage of the Slides API.
- Prints the number of slides and elments in a sample presentation.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Slides API.
+ Prints the number of slides and elements in a sample presentation.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('slides', 'v1', credentials=creds)
+ try:
+ service = build("slides", "v1", credentials=creds)
- # Call the Slides API
- presentation = service.presentations().get(
- presentationId=PRESENTATION_ID).execute()
- slides = presentation.get('slides')
+ # Call the Slides API
+ presentation = (
+ service.presentations().get(presentationId=PRESENTATION_ID).execute()
+ )
+ slides = presentation.get("slides")
- print('The presentation contains {} slides:'.format(len(slides)))
- for i, slide in enumerate(slides):
- print('- Slide #{} contains {} elements.'.format(
- i + 1, len(slide.get('pageElements'))))
- except HttpError as err:
- print(err)
+ print(f"The presentation contains {len(slides)} slides:")
+ for i, slide in enumerate(slides):
+ print(
+ f"- Slide #{i + 1} contains"
+ f" {len(slide.get('pageElements'))} elements."
+ )
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END slides_quickstart]
diff --git a/slides/snippets/base_test.py b/slides/snippets/base_test.py
index 7bcd1ac7..60952df2 100644
--- a/slides/snippets/base_test.py
+++ b/slides/snippets/base_test.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import print_function
-
import sys
import unittest
@@ -24,155 +22,150 @@
class BaseTest(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.credentials = cls.create_credentials()
- http = cls.credentials.authorize(httplib2.Http())
- cls.credentials.refresh(http)
- cls.service = build('slides', 'v1', http=http)
- cls.drive_service = build('drive', 'v3', http=http)
- cls.sheets_service = build('sheets', 'v4', http=http)
- # Hide STDOUT output generated by snippets.
- cls.stdout = sys.stdout
- sys.stdout = None
-
- @classmethod
- def tearDownClass(cls):
- # Restore STDOUT.
- sys.stdout = cls.stdout
-
- @classmethod
- def create_credentials(cls):
- credentials = GoogleCredentials.get_application_default()
- scope = [
- 'https://www.googleapis.com/auth/drive',
- ]
- return credentials.create_scoped(scope)
-
- def setUp(self):
- self.files_to_delete = []
-
- def tearDown(self):
- for file_id in self.files_to_delete:
- try:
- self.drive_service.files().delete(fileId=file_id).execute()
- except errors.HttpError:
- print('Unable to delete file %s' % file_id, file=sys.stderr)
-
- def delete_file_on_cleanup(self, file_id):
- self.files_to_delete.append(file_id)
-
- def create_test_presentation(self):
- presentation = {
- 'title': 'Test Preso'
- }
- presentation = self.service.presentations().create(
- body=presentation).execute()
- self.delete_file_on_cleanup(presentation.get('presentationId'))
- return presentation.get('presentationId')
-
- def add_slides(self, presentation_id, num, layout='TITLE_AND_TWO_COLUMNS'):
- requests = []
- slide_ids = []
- for i in range(num):
- slide_id = 'slide_{0}'.format(i)
- slide_ids.append(slide_id)
- requests.append({
- 'createSlide': {
- 'objectId': slide_ids[i],
- 'slideLayoutReference': {
- 'predefinedLayout': layout
- }
- }
- })
- body = {
- 'requests': requests
- }
- self.service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- return slide_ids
-
- def create_test_textbox(self, presentation_id, page_id):
- box_id = 'MyTextBox_01'
- pt350 = {
- 'magnitude': 350,
- 'unit': 'PT'
- }
- requests = []
- requests.append({
- 'createShape': {
- 'objectId': box_id,
- 'shapeType': 'TEXT_BOX',
- 'elementProperties': {
- 'pageObjectId': page_id,
- 'size': {
- 'height': pt350,
- 'width': pt350
+
+ @classmethod
+ def setUpClass(cls):
+ cls.credentials = cls.create_credentials()
+ http = cls.credentials.authorize(httplib2.Http())
+ cls.credentials.refresh(http)
+ cls.service = build("slides", "v1", http=http)
+ cls.drive_service = build("drive", "v3", http=http)
+ cls.sheets_service = build("sheets", "v4", http=http)
+ # Hide STDOUT output generated by snippets.
+ cls.stdout = sys.stdout
+ sys.stdout = None
+
+ @classmethod
+ def tearDownClass(cls):
+ # Restore STDOUT.
+ sys.stdout = cls.stdout
+
+ @classmethod
+ def create_credentials(cls):
+ credentials = GoogleCredentials.get_application_default()
+ scope = [
+ "https://www.googleapis.com/auth/drive",
+ ]
+ return credentials.create_scoped(scope)
+
+ def setUp(self):
+ self.files_to_delete = []
+
+ def tearDown(self):
+ for file_id in self.files_to_delete:
+ try:
+ self.drive_service.files().delete(fileId=file_id).execute()
+ except errors.HttpError:
+ print(f"Unable to delete file {file_id}", file=sys.stderr)
+
+ def delete_file_on_cleanup(self, file_id):
+ self.files_to_delete.append(file_id)
+
+ def create_test_presentation(self):
+ presentation = {"title": "Test Preso"}
+ presentation = (
+ self.service.presentations().create(body=presentation).execute()
+ )
+ self.delete_file_on_cleanup(presentation.get("presentationId"))
+ return presentation.get("presentationId")
+
+ def add_slides(self, presentation_id, num, layout="TITLE_AND_TWO_COLUMNS"):
+ requests = []
+ slide_ids = []
+ for i in range(num):
+ slide_id = f"slide_{i}"
+ slide_ids.append(slide_id)
+ requests.append(
+ {
+ "createSlide": {
+ "objectId": slide_ids[i],
+ "slideLayoutReference": {"predefinedLayout": layout},
+ }
+ }
+ )
+ body = {"requests": requests}
+ self.service.presentations().batchUpdate(
+ presentationId=presentation_id, body=body
+ ).execute()
+ return slide_ids
+
+ def create_test_textbox(self, presentation_id, page_id):
+ box_id = "MyTextBox_01"
+ pt350 = {"magnitude": 350, "unit": "PT"}
+ requests = []
+ requests.append(
+ {
+ "createShape": {
+ "objectId": box_id,
+ "shapeType": "TEXT_BOX",
+ "elementProperties": {
+ "pageObjectId": page_id,
+ "size": {"height": pt350, "width": pt350},
+ "transform": {
+ "scaleX": 1,
+ "scaleY": 1,
+ "translateX": 350,
+ "translateY": 100,
+ "unit": "PT",
},
- 'transform': {
- 'scaleX': 1,
- 'scaleY': 1,
- 'translateX': 350,
- 'translateY': 100,
- 'unit': 'PT'
- }
- }
+ },
}
- })
- requests.append({
- 'insertText': {
- 'objectId': box_id,
- 'insertionIndex': 0,
- 'text': 'New Box Text Inserted'
- }
- })
-
- body = {
- 'requests': requests
}
- response = self.service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- return response.get('replies')[0].get('createShape').get('objectId')
-
- def create_test_sheets_chart(
- self, presentation_id, page_id, spreadsheet_id, sheet_chart_id):
- chart_id = 'MyChart_01'
- emu4M = {
- 'magnitude': 4000000,
- 'unit': 'EMU'
+ )
+ requests.append(
+ {
+ "insertText": {
+ "objectId": box_id,
+ "insertionIndex": 0,
+ "text": "New Box Text Inserted",
+ }
}
- requests = []
- requests.append({
- 'createSheetsChart': {
- 'objectId': chart_id,
- 'spreadsheetId': spreadsheet_id,
- 'chartId': sheet_chart_id,
- 'linkingMode': 'LINKED',
- 'elementProperties': {
- 'pageObjectId': page_id,
- 'size': {
- 'height': emu4M,
- 'width': emu4M
+ )
+
+ body = {"requests": requests}
+ response = (
+ self.service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ return response.get("replies")[0].get("createShape").get("objectId")
+
+ def create_test_sheets_chart(
+ self, presentation_id, page_id, spreadsheet_id, sheet_chart_id
+ ):
+ chart_id = "MyChart_01"
+ emu4M = {"magnitude": 4000000, "unit": "EMU"}
+ requests = []
+ requests.append(
+ {
+ "createSheetsChart": {
+ "objectId": chart_id,
+ "spreadsheetId": spreadsheet_id,
+ "chartId": sheet_chart_id,
+ "linkingMode": "LINKED",
+ "elementProperties": {
+ "pageObjectId": page_id,
+ "size": {"height": emu4M, "width": emu4M},
+ "transform": {
+ "scaleX": 1,
+ "scaleY": 1,
+ "translateX": 100000,
+ "translateY": 100000,
+ "unit": "EMU",
},
- 'transform': {
- 'scaleX': 1,
- 'scaleY': 1,
- 'translateX': 100000,
- 'translateY': 100000,
- 'unit': 'EMU'
- }
- }
+ },
}
- })
-
- body = {
- 'requests': requests
}
- response = self.service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- return response.get('replies')[0] \
- .get('createSheetsChart').get('objectId')
+ )
+
+ body = {"requests": requests}
+ response = (
+ self.service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ return response.get("replies")[0].get("createSheetsChart").get("objectId")
-if __name__ == '__main__':
- unittest.main()
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/slides_copy_presentation.py b/slides/snippets/slides_copy_presentation.py
new file mode 100644
index 00000000..fc4c0343
--- /dev/null
+++ b/slides/snippets/slides_copy_presentation.py
@@ -0,0 +1,53 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_copy_presentation]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def copy_presentation(presentation_id, copy_title):
+ """
+ Creates the copy Presentation the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ drive_service = build("drive", "v3", credentials=creds)
+ body = {"name": copy_title}
+ drive_response = (
+ drive_service.files().copy(fileId=presentation_id, body=body).execute()
+ )
+ presentation_copy_id = drive_response.get("id")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Presentations not copied")
+ return error
+
+ return presentation_copy_id
+ # [END slides_copy_presentation]
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, Page_id of slides whose list needs
+ # to be submitted.
+ copy_presentation("16eRvJHRrM8Sej5YA0yCHVzQCPLz31-JhbOa4XpP8Yko", "wspace")
diff --git a/slides/snippets/slides_create_bulleted_text.py b/slides/snippets/slides_create_bulleted_text.py
new file mode 100644
index 00000000..e7051222
--- /dev/null
+++ b/slides/snippets/slides_create_bulleted_text.py
@@ -0,0 +1,67 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_bulleted_text]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_bulleted_text(presentation_id, shape_id):
+ """
+ Run create_bulleted_text the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ slides_service = build("slides", "v1", credentials=creds)
+ # Add arrow-diamond-disc bullets to all text in the shape.
+ requests = [
+ {
+ "createParagraphBullets": {
+ "objectId": shape_id,
+ "textRange": {"type": "ALL"},
+ "bulletPreset": "BULLET_ARROW_DIAMOND_DISC",
+ }
+ }
+ ]
+
+ # Execute the requests.
+ body = {"requests": requests}
+ response = (
+ slides_service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ print(f"Added bullets to text in shape with ID: {shape_id}")
+
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id and shape_id
+ # to be submitted.
+ create_bulleted_text(
+ "1VD1xmi1-9DonI4zmCKENTzlVxIL5SdGGTmbHmnBjQ1E", "MyTextBox_9"
+ )
+
+# [END slides_create_bulleted_text]
diff --git a/slides/snippets/slides_create_image.py b/slides/snippets/slides_create_image.py
new file mode 100644
index 00000000..e0152156
--- /dev/null
+++ b/slides/snippets/slides_create_image.py
@@ -0,0 +1,85 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_image]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_image(presentation_id, page_id):
+ """
+ Creates images the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("slides", "v1", credentials=creds)
+ # pylint: disable = invalid-name
+ IMAGE_URL = (
+ "https://www.google.com/images/branding/"
+ "googlelogo/2x/googlelogo_color_272x92dp.png"
+ )
+ # pylint: disable=invalid-name
+ requests = []
+ image_id = "MyImage_11"
+ emu4M = {"magnitude": 4000000, "unit": "EMU"}
+ requests.append(
+ {
+ "createImage": {
+ "objectId": image_id,
+ "url": IMAGE_URL,
+ "elementProperties": {
+ "pageObjectId": page_id,
+ "size": {"height": emu4M, "width": emu4M},
+ "transform": {
+ "scaleX": 1,
+ "scaleY": 1,
+ "translateX": 100000,
+ "translateY": 100000,
+ "unit": "EMU",
+ },
+ },
+ }
+ }
+ )
+
+ # Execute the request.
+ body = {"requests": requests}
+ response = (
+ service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ create_image_response = response.get("replies")[0].get("createImage")
+ print(f"Created image with ID: {(create_image_response.get('objectId'))}")
+
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Images not created")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, Page_id of slides whose list needs
+ # to be submitted.
+ create_image("12SQU9Ik-ShXecJoMtT-LlNwEPiFR7AadnxV2KiBXCnE", "My2ndpage")
+ # [END slides_create_image]
diff --git a/slides/snippets/slides_create_presentation.py b/slides/snippets/slides_create_presentation.py
new file mode 100644
index 00000000..2f683e6c
--- /dev/null
+++ b/slides/snippets/slides_create_presentation.py
@@ -0,0 +1,53 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_presentation]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_presentation(title):
+ """
+ Creates the Presentation the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("slides", "v1", credentials=creds)
+
+ body = {"title": title}
+ presentation = service.presentations().create(body=body).execute()
+ print(
+ f"Created presentation with ID:{(presentation.get('presentationId'))}"
+ )
+ return presentation
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("presentation not created")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the title of the presentation
+
+ create_presentation("finalp")
+
+# [END slides_create_presentation]
diff --git a/slides/snippets/slides_create_sheets_chart.py b/slides/snippets/slides_create_sheets_chart.py
new file mode 100644
index 00000000..9efa3d64
--- /dev/null
+++ b/slides/snippets/slides_create_sheets_chart.py
@@ -0,0 +1,90 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_sheets_chart]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_sheets_chart(
+ presentation_id, page_id, spreadsheet_id, sheet_chart_id
+):
+ """
+ create_sheets_chart the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ slides_service = build("slides", "v1", credentials=creds)
+ # Embed a Sheets chart (indicated by the spreadsheet_id and
+ # sheet_chart_id) onto a page in the presentation.
+ # Setting the linking mode as "LINKED" allows the
+ # chart to be refreshed if the Sheets version is updated.
+
+ emu4m = {"magnitude": 4000000, "unit": "EMU"}
+
+ presentation_chart_id = "MyEmbeddedChart"
+ requests = [
+ {
+ "createSheetsChart": {
+ "objectId": presentation_chart_id,
+ "spreadsheetId": spreadsheet_id,
+ "chartId": sheet_chart_id,
+ "linkingMode": "LINKED",
+ "elementProperties": {
+ "pageObjectId": page_id,
+ "size": {"height": emu4m, "width": emu4m},
+ "transform": {
+ "scaleX": 1,
+ "scaleY": 1,
+ "translateX": 100000,
+ "translateY": 100000,
+ "unit": "EMU",
+ },
+ },
+ }
+ }
+ ]
+
+ # Execute the request.
+ body = {"requests": requests}
+ response = (
+ slides_service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ print(f"Added a linked Sheets chart with ID: {presentation_chart_id}")
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, Page_id of slides
+ # spreadsheet_id and sheet_chart_id to be submitted.
+ create_sheets_chart(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
+ "FIRSTSLIDE",
+ "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM",
+ "1107320627",
+ )
+
+# [END slides_create_sheets_chart]
diff --git a/slides/snippets/slides_create_slide.py b/slides/snippets/slides_create_slide.py
new file mode 100644
index 00000000..fafbfa78
--- /dev/null
+++ b/slides/snippets/slides_create_slide.py
@@ -0,0 +1,72 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_slide]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_slide(presentation_id, page_id):
+ """
+ Creates the Presentation the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.\n
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("slides", "v1", credentials=creds)
+ # Add a slide at index 1 using the predefined
+ # 'TITLE_AND_TWO_COLUMNS' layout and the ID page_id.
+ requests = [
+ {
+ "createSlide": {
+ "objectId": page_id,
+ "insertionIndex": "1",
+ "slideLayoutReference": {
+ "predefinedLayout": "TITLE_AND_TWO_COLUMNS"
+ },
+ }
+ }
+ ]
+
+ # If you wish to populate the slide with elements,
+ # add element create requests here, using the page_id.
+
+ # Execute the request.
+ body = {"requests": requests}
+ response = (
+ service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ create_slide_response = response.get("replies")[0].get("createSlide")
+ print(f"Created slide with ID:{(create_slide_response.get('objectId'))}")
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Slides not created")
+ return error
+
+ return response
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, Page_id of slides whose list needs
+ # to be submitted.
+ create_slide("12SQU9Ik-ShXecJoMtT-LlNwEPiFR7AadnxV2KiBXCnE", "My4ndpage")
+ # [END slides_create_slide]
diff --git a/slides/snippets/slides_create_textbox_with_text.py b/slides/snippets/slides_create_textbox_with_text.py
new file mode 100644
index 00000000..d3879d19
--- /dev/null
+++ b/slides/snippets/slides_create_textbox_with_text.py
@@ -0,0 +1,89 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_create_textbox_with_text]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def create_textbox_with_text(presentation_id, page_id):
+ """
+ Creates the textbox with text, the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("slides", "v1", credentials=creds)
+ # Create a new square textbox, using the supplied element ID.
+ element_id = "MyTextBox_10"
+ pt350 = {"magnitude": 350, "unit": "PT"}
+ requests = [
+ {
+ "createShape": {
+ "objectId": element_id,
+ "shapeType": "TEXT_BOX",
+ "elementProperties": {
+ "pageObjectId": page_id,
+ "size": {"height": pt350, "width": pt350},
+ "transform": {
+ "scaleX": 1,
+ "scaleY": 1,
+ "translateX": 350,
+ "translateY": 100,
+ "unit": "PT",
+ },
+ },
+ }
+ },
+ # Insert text into the box, using the supplied element ID.
+ {
+ "insertText": {
+ "objectId": element_id,
+ "insertionIndex": 0,
+ "text": "New Box Text Inserted!",
+ }
+ },
+ ]
+
+ # Execute the request.
+ body = {"requests": requests}
+ response = (
+ service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ create_shape_response = response.get("replies")[0].get("createShape")
+ print(f"Created textbox with ID:{(create_shape_response.get('objectId'))}")
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+
+ return error
+
+ return response
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, Page_id of slides whose list needs
+ # to be submitted.
+ create_textbox_with_text(
+ "12SQU9Ik-ShXecJoMtT-LlNwEPiFR7AadnxV2KiBXCnE", "Myfirstpage"
+ )
+
+# [END slides_create_textbox_with_text]
diff --git a/slides/snippets/slides_image_merging.py b/slides/snippets/slides_image_merging.py
new file mode 100644
index 00000000..f27161c8
--- /dev/null
+++ b/slides/snippets/slides_image_merging.py
@@ -0,0 +1,115 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_image_merging]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def image_merging(template_presentation_id, image_url, customer_name):
+ """image_merging require template_presentation_id,
+ image_url and customer_name
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ slides_service = build("slides", "v1", credentials=creds)
+ drive_service = build("drive", "v3", credentials=creds)
+ logo_url = image_url
+
+ customer_graphic_url = image_url
+
+ # Duplicate the template presentation using the Drive API.
+ copy_title = customer_name + " presentation"
+ drive_response = (
+ drive_service.files()
+ .copy(fileId=template_presentation_id, body={"name": copy_title})
+ .execute()
+ )
+ presentation_copy_id = drive_response.get("id")
+
+ # Create the image merge (replaceAllShapesWithImage) requests.
+ requests = []
+ requests.append(
+ {
+ "replaceAllShapesWithImage": {
+ "imageUrl": logo_url,
+ "replaceMethod": "CENTER_INSIDE",
+ "containsText": {
+ "text": "{{company-logo}}",
+ "matchCase": True,
+ },
+ }
+ }
+ )
+ requests.append(
+ {
+ "replaceAllShapesWithImage": {
+ "imageUrl": customer_graphic_url,
+ "replaceMethod": "CENTER_INSIDE",
+ "containsText": {
+ "text": "{{customer-graphic}}",
+ "matchCase": True,
+ },
+ }
+ }
+ )
+
+ # Execute the requests.
+ body = {"requests": requests}
+ response = (
+ slides_service.presentations()
+ .batchUpdate(presentationId=presentation_copy_id, body=body)
+ .execute()
+ )
+
+ # Count the number of replacements made.
+ num_replacements = 0
+
+ for reply in response.get("replies"):
+ # add below line
+
+ if reply.get("occurrencesChanged") is not None:
+ # end tag
+ num_replacements += reply.get("replaceAllShapesWithImage").get(
+ "occurrencesChanged"
+ )
+
+ print(f"Created merged presentation with ID:{presentation_copy_id}")
+ print(f"Replaced {num_replacements} shapes with images")
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Images is not merged")
+ return error
+
+ return response
+
+
+if __name__ == "__main__":
+ # Put the template_presentation_id, image_url and customer_name
+
+ image_merging(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
+ "https://www.google.com/images/branding/"
+ "googlelogo/2x/googlelogo_color_272x92dp.png",
+ "Fake Customer",
+ )
+
+ # [END slides_image_merging]
diff --git a/slides/snippets/slides_refresh_sheets_chart.py b/slides/snippets/slides_refresh_sheets_chart.py
new file mode 100644
index 00000000..a0179a4f
--- /dev/null
+++ b/slides/snippets/slides_refresh_sheets_chart.py
@@ -0,0 +1,57 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_refresh_sheets_chart]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def refresh_sheets_chart(presentation_id, presentation_chart_id):
+ """
+ refresh_sheets_chart the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ slides_service = build("slides", "v1", credentials=creds)
+ # Refresh an existing linked Sheets chart embedded in a presentation.
+ requests = [{"refreshSheetsChart": {"objectId": presentation_chart_id}}]
+
+ # Execute the request.
+ body = {"requests": requests}
+ response = (
+ slides_service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ print(f"Refreshed a linked Sheets chart with ID:{presentation_chart_id}")
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, presentation_chart_id
+ # to be submitted.
+ refresh_sheets_chart(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4", "1107320627"
+ )
+ # [END slides_refresh_sheets_chart]
diff --git a/slides/snippets/slides_simple_text_replace.py b/slides/snippets/slides_simple_text_replace.py
new file mode 100644
index 00000000..bd4adaaa
--- /dev/null
+++ b/slides/snippets/slides_simple_text_replace.py
@@ -0,0 +1,72 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_simple_text_replace]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def simple_text_replace(presentation_id, shape_id, replacement_text):
+ """
+ Run simple_text_replace the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ slides_service = build("slides", "v1", credentials=creds)
+ # Remove existing text in the shape, then insert new text.
+ requests = []
+ requests.append(
+ {"deleteText": {"objectId": shape_id, "textRange": {"type": "ALL"}}}
+ )
+ requests.append(
+ {
+ "insertText": {
+ "objectId": shape_id,
+ "insertionIndex": 0,
+ "text": replacement_text,
+ }
+ }
+ )
+
+ # Execute the requests.
+ body = {"requests": requests}
+ response = (
+ slides_service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ print(f"Replaced text in shape with ID: {shape_id}")
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ print("Text is not merged")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, shape_id and replacement_text
+ simple_text_replace(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
+ "MyTextBox_6",
+ "GWSpace_now",
+ )
+
+# [END slides_simple_text_replace]
diff --git a/slides/snippets/slides_snippets.py b/slides/snippets/slides_snippets.py
deleted file mode 100644
index 1d57a56c..00000000
--- a/slides/snippets/slides_snippets.py
+++ /dev/null
@@ -1,523 +0,0 @@
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-
-class SlidesSnippets(object):
- def __init__(self, service, drive_service, sheets_service, credentials):
- self.service = service
- self.drive_service = drive_service
- self.sheets_service = sheets_service
- self.credentials = credentials
-
- def create_presentation(self, title):
- slides_service = self.service
- # [START slides_create_presentation]
- body = {
- 'title': title
- }
- presentation = slides_service.presentations() \
- .create(body=body).execute()
- print('Created presentation with ID: {0}'.format(
- presentation.get('presentationId')))
- # [END slides_create_presentation]
- return presentation
-
- def copy_presentation(self, presentation_id, copy_title):
- drive_service = self.drive_service
- # [START slides_copy_presentation]
- body = {
- 'name': copy_title
- }
- drive_response = drive_service.files().copy(
- fileId=presentation_id, body=body).execute()
- presentation_copy_id = drive_response.get('id')
- # [END slides_copy_presentation]
- return presentation_copy_id
-
- def create_slide(self, presentation_id, page_id):
- slides_service = self.service
- # [START slides_create_slide]
- # Add a slide at index 1 using the predefined
- # 'TITLE_AND_TWO_COLUMNS' layout and the ID page_id.
- requests = [
- {
- 'createSlide': {
- 'objectId': page_id,
- 'insertionIndex': '1',
- 'slideLayoutReference': {
- 'predefinedLayout': 'TITLE_AND_TWO_COLUMNS'
- }
- }
- }
- ]
-
- # If you wish to populate the slide with elements,
- # add element create requests here, using the page_id.
-
- # Execute the request.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations() \
- .batchUpdate(presentationId=presentation_id, body=body).execute()
- create_slide_response = response.get('replies')[0].get('createSlide')
- print('Created slide with ID: {0}'.format(
- create_slide_response.get('objectId')))
- # [END slides_create_slide]
- return response
-
- def create_textbox_with_text(self, presentation_id, page_id):
- slides_service = self.service
- # [START slides_create_textbox_with_text]
- # Create a new square textbox, using the supplied element ID.
- element_id = 'MyTextBox_01'
- pt350 = {
- 'magnitude': 350,
- 'unit': 'PT'
- }
- requests = [
- {
- 'createShape': {
- 'objectId': element_id,
- 'shapeType': 'TEXT_BOX',
- 'elementProperties': {
- 'pageObjectId': page_id,
- 'size': {
- 'height': pt350,
- 'width': pt350
- },
- 'transform': {
- 'scaleX': 1,
- 'scaleY': 1,
- 'translateX': 350,
- 'translateY': 100,
- 'unit': 'PT'
- }
- }
- }
- },
-
- # Insert text into the box, using the supplied element ID.
- {
- 'insertText': {
- 'objectId': element_id,
- 'insertionIndex': 0,
- 'text': 'New Box Text Inserted!'
- }
- }
- ]
-
- # Execute the request.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations() \
- .batchUpdate(presentationId=presentation_id, body=body).execute()
- create_shape_response = response.get('replies')[0].get('createShape')
- print('Created textbox with ID: {0}'.format(
- create_shape_response.get('objectId')))
- # [END slides_create_textbox_with_text]
- return response
-
- def create_image(self, presentation_id, page_id):
- slides_service = self.service
- # [START slides_create_image]
- # Create a new image, using the supplied object ID,
- # with content downloaded from IMAGE_URL.
- IMAGE_URL = ('https://www.google.com/images/branding/'
- 'googlelogo/2x/googlelogo_color_272x92dp.png')
- requests = []
- image_id = 'MyImage_01'
- emu4M = {
- 'magnitude': 4000000,
- 'unit': 'EMU'
- }
- requests.append({
- 'createImage': {
- 'objectId': image_id,
- 'url': IMAGE_URL,
- 'elementProperties': {
- 'pageObjectId': page_id,
- 'size': {
- 'height': emu4M,
- 'width': emu4M
- },
- 'transform': {
- 'scaleX': 1,
- 'scaleY': 1,
- 'translateX': 100000,
- 'translateY': 100000,
- 'unit': 'EMU'
- }
- }
- }
- })
-
- # Execute the request.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations() \
- .batchUpdate(presentationId=presentation_id, body=body).execute()
- create_image_response = response.get('replies')[0].get('createImage')
- print('Created image with ID: {0}'.format(
- create_image_response.get('objectId')))
-
- # [END slides_create_image]
- return response
-
- def text_merging(self, template_presentation_id, data_spreadsheet_id):
- slides_service = self.service
- sheets_service = self.sheets_service
- drive_service = self.drive_service
- responses = []
- # [START slides_text_merging]
- # Use the Sheets API to load data, one record per row.
- data_range_notation = 'Customers!A2:M6'
- sheets_response = sheets_service.spreadsheets().values().get(
- spreadsheetId=data_spreadsheet_id,
- range=data_range_notation).execute()
- values = sheets_response.get('values')
-
- # For each record, create a new merged presentation.
- for row in values:
- customer_name = row[2] # name in column 3
- case_description = row[5] # case description in column 6
- total_portfolio = row[11] # total portfolio in column 12
-
- # Duplicate the template presentation using the Drive API.
- copy_title = customer_name + ' presentation'
- body = {
- 'name': copy_title
- }
- drive_response = drive_service.files().copy(
- fileId=template_presentation_id, body=body).execute()
- presentation_copy_id = drive_response.get('id')
-
- # Create the text merge (replaceAllText) requests
- # for this presentation.
- requests = [
- {
- 'replaceAllText': {
- 'containsText': {
- 'text': '{{customer-name}}',
- 'matchCase': True
- },
- 'replaceText': customer_name
- }
- },
- {
- 'replaceAllText': {
- 'containsText': {
- 'text': '{{case-description}}',
- 'matchCase': True
- },
- 'replaceText': case_description
- }
- },
- {
- 'replaceAllText': {
- 'containsText': {
- 'text': '{{total-portfolio}}',
- 'matchCase': True
- },
- 'replaceText': total_portfolio
- }
- }
- ]
-
- # Execute the requests for this presentation.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_copy_id, body=body).execute()
- # [START_EXCLUDE silent]
- responses.append(response)
- # [END_EXCLUDE]
- # Count the total number of replacements made.
- num_replacements = 0
- for reply in response.get('replies'):
- num_replacements += reply.get('replaceAllText') \
- .get('occurrencesChanged')
- print('Created presentation for %s with ID: %s' %
- (customer_name, presentation_copy_id))
- print('Replaced %d text instances' % num_replacements)
-
- # [END slides_text_merging]
- return responses
-
- def image_merging(self, template_presentation_id,
- image_url, customer_name):
- slides_service = self.service
- drive_service = self.drive_service
- logo_url = image_url
- customer_graphic_url = image_url
-
- # [START slides_image_merging]
- # Duplicate the template presentation using the Drive API.
- copy_title = customer_name + ' presentation'
- drive_response = drive_service.files().copy(
- fileId=template_presentation_id,
- body={'name': copy_title}).execute()
- presentation_copy_id = drive_response.get('id')
-
- # Create the image merge (replaceAllShapesWithImage) requests.
- requests = []
- requests.append({
- 'replaceAllShapesWithImage': {
- 'imageUrl': logo_url,
- 'replaceMethod': 'CENTER_INSIDE',
- 'containsText': {
- 'text': '{{company-logo}}',
- 'matchCase': True
- }
- }
- })
- requests.append({
- 'replaceAllShapesWithImage': {
- 'imageUrl': customer_graphic_url,
- 'replaceMethod': 'CENTER_INSIDE',
- 'containsText': {
- 'text': '{{customer-graphic}}',
- 'matchCase': True
- }
- }
- })
-
- # Execute the requests.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_copy_id, body=body).execute()
-
- # Count the number of replacements made.
- num_replacements = 0
- for reply in response.get('replies'):
- num_replacements += reply.get('replaceAllShapesWithImage') \
- .get('occurrencesChanged')
- print('Created merged presentation with ID: {0}'
- .format(presentation_copy_id))
- print('Replaced %d shapes with images.' % num_replacements)
- # [END slides_image_merging]
- return response
-
- def simple_text_replace(self, presentation_id, shape_id, replacement_text):
- slides_service = self.service
- # [START slides_simple_text_replace]
- # Remove existing text in the shape, then insert new text.
- requests = []
- requests.append({
- 'deleteText': {
- 'objectId': shape_id,
- 'textRange': {
- 'type': 'ALL'
- }
- }
- })
- requests.append({
- 'insertText': {
- 'objectId': shape_id,
- 'insertionIndex': 0,
- 'text': replacement_text
- }
- })
-
- # Execute the requests.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- print('Replaced text in shape with ID: {0}'.format(shape_id))
- # [END slides_simple_text_replace]
- return response
-
- def text_style_update(self, presentation_id, shape_id):
- slides_service = self.service
- # [START slides_text_style_update]
- # Update the text style so that the first 5 characters are bolded
- # and italicized, the next 5 are displayed in blue 14 pt Times
- # New Roman font, and the next 5 are hyperlinked.
- requests = [
- {
- 'updateTextStyle': {
- 'objectId': shape_id,
- 'textRange': {
- 'type': 'FIXED_RANGE',
- 'startIndex': 0,
- 'endIndex': 5
- },
- 'style': {
- 'bold': True,
- 'italic': True
- },
- 'fields': 'bold,italic'
- }
- },
- {
- 'updateTextStyle': {
- 'objectId': shape_id,
- 'textRange': {
- 'type': 'FIXED_RANGE',
- 'startIndex': 5,
- 'endIndex': 10
- },
- 'style': {
- 'fontFamily': 'Times New Roman',
- 'fontSize': {
- 'magnitude': 14,
- 'unit': 'PT'
- },
- 'foregroundColor': {
- 'opaqueColor': {
- 'rgbColor': {
- 'blue': 1.0,
- 'green': 0.0,
- 'red': 0.0
- }
- }
- }
- },
- 'fields': 'foregroundColor,fontFamily,fontSize'
- }
- },
- {
- 'updateTextStyle': {
- 'objectId': shape_id,
- 'textRange': {
- 'type': 'FIXED_RANGE',
- 'startIndex': 10,
- 'endIndex': 15
- },
- 'style': {
- 'link': {
- 'url': 'www.example.com'
- }
- },
- 'fields': 'link'
- }
- }
- ]
-
- # Execute the requests.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- print('Updated the text style for shape with ID: {0}'.format(shape_id))
- # [END slides_text_style_update]
- return response
-
- def create_bulleted_text(self, presentation_id, shape_id):
- slides_service = self.service
- # [START slides_create_bulleted_text]
- # Add arrow-diamond-disc bullets to all text in the shape.
- requests = [
- {
- 'createParagraphBullets': {
- 'objectId': shape_id,
- 'textRange': {
- 'type': 'ALL'
- },
- 'bulletPreset': 'BULLET_ARROW_DIAMOND_DISC'
- }
- }
- ]
-
- # Execute the requests.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- print('Added bullets to text in shape with ID: {0}'.format(shape_id))
- # [END slides_create_bulleted_text]
- return response
-
- def create_sheets_chart(self, presentation_id, page_id, spreadsheet_id,
- sheet_chart_id):
- slides_service = self.service
- # [START slides_create_sheets_chart]
- # Embed a Sheets chart (indicated by the spreadsheet_id and
- # sheet_chart_id) onto a page in the presentation.
- # Setting the linking mode as "LINKED" allows the
- # chart to be refreshed if the Sheets version is updated.
- emu4M = {
- 'magnitude': 4000000,
- 'unit': 'EMU'
- }
- presentation_chart_id = 'MyEmbeddedChart'
- requests = [
- {
- 'createSheetsChart': {
- 'objectId': presentation_chart_id,
- 'spreadsheetId': spreadsheet_id,
- 'chartId': sheet_chart_id,
- 'linkingMode': 'LINKED',
- 'elementProperties': {
- 'pageObjectId': page_id,
- 'size': {
- 'height': emu4M,
- 'width': emu4M
- },
- 'transform': {
- 'scaleX': 1,
- 'scaleY': 1,
- 'translateX': 100000,
- 'translateY': 100000,
- 'unit': 'EMU'
- }
- }
- }
- }
- ]
-
- # Execute the request.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- print('Added a linked Sheets chart with ID: {0}'.format(
- presentation_chart_id))
- # [END slides_create_sheets_chart]
- return response
-
- def refresh_sheets_chart(self, presentation_id, presentation_chart_id):
- slides_service = self.service
- # [START slides_refresh_sheets_chart]
- # Refresh an existing linked Sheets chart embedded in a presentation.
- requests = [
- {
- 'refreshSheetsChart': {
- 'objectId': presentation_chart_id
- }
- }
- ]
-
- # Execute the request.
- body = {
- 'requests': requests
- }
- response = slides_service.presentations().batchUpdate(
- presentationId=presentation_id, body=body).execute()
- print('Refreshed a linked Sheets chart with ID: {0}'
- .format(presentation_chart_id))
- # [END slides_refresh_sheets_chart]
- return response
diff --git a/slides/snippets/slides_text_merging.py b/slides/snippets/slides_text_merging.py
new file mode 100644
index 00000000..690ac1ab
--- /dev/null
+++ b/slides/snippets/slides_text_merging.py
@@ -0,0 +1,129 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_text_merging]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def text_merging(template_presentation_id, data_spreadsheet_id):
+ """
+ Run Text merging the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+
+ try:
+ service = build("slides", "v1", credentials=creds)
+ sheets_service = build("sheets", "v4", credentials=creds)
+ drive_service = build("drive", "v3", credentials=creds)
+ # Use the Sheets API to load data, one record per row.
+ data_range_notation = "Customers!A2:M6"
+ sheets_response = (
+ sheets_service.spreadsheets()
+ .values()
+ .get(spreadsheetId=data_spreadsheet_id, range=data_range_notation)
+ .execute()
+ )
+ values = sheets_response.get("values")
+
+ # For each record, create a new merged presentation.
+ for row in values:
+ customer_name = row[2] # name in column 3
+ case_description = row[5] # case description in column 6
+ total_portfolio = row[11] # total portfolio in column 12
+
+ # Duplicate the template presentation using the Drive API.
+ copy_title = customer_name + " presentation"
+ body = {"name": copy_title}
+ drive_response = (
+ drive_service.files()
+ .copy(fileId=template_presentation_id, body=body)
+ .execute()
+ )
+ presentation_copy_id = drive_response.get("id")
+
+ # Create the text merge (replaceAllText) requests
+ # for this presentation.
+ requests = [
+ {
+ "replaceAllText": {
+ "containsText": {
+ "text": "{{customer-name}}",
+ "matchCase": True,
+ },
+ "replaceText": customer_name,
+ }
+ },
+ {
+ "replaceAllText": {
+ "containsText": {
+ "text": "{{case-description}}",
+ "matchCase": True,
+ },
+ "replaceText": case_description,
+ }
+ },
+ {
+ "replaceAllText": {
+ "containsText": {
+ "text": "{{total-portfolio}}",
+ "matchCase": True,
+ },
+ "replaceText": total_portfolio,
+ }
+ },
+ ]
+
+ # Execute the requests for this presentation.
+ body = {"requests": requests}
+ response = (
+ service.presentations()
+ .batchUpdate(presentationId=presentation_copy_id, body=body)
+ .execute()
+ )
+
+ # Count the total number of replacements made.
+ num_replacements = 0
+ for reply in response.get("replies"):
+ if reply.get("occurrencesChanged") is not None:
+ num_replacements += reply.get("replaceAllText").get(
+ "occurrencesChanged"
+ )
+ print(
+ "Created presentation for "
+ f"{customer_name} with ID: {presentation_copy_id}"
+ )
+ print(f"Replaced {num_replacements} text instances")
+
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the template_presentation_id, data_spreadsheet_id
+ # of slides
+
+ text_merging(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",
+ "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM",
+ )
+ # [END slides_text_merging]
diff --git a/slides/snippets/slides_text_style_update.py b/slides/snippets/slides_text_style_update.py
new file mode 100644
index 00000000..5615fe6e
--- /dev/null
+++ b/slides/snippets/slides_text_style_update.py
@@ -0,0 +1,109 @@
+"""
+Copyright 2022 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.
+"""
+
+# [START slides_text_style_update]
+import google.auth
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+
+def text_style_update(presentation_id, shape_id):
+ """
+ create_sheets_chart the user has access to.
+ Load pre-authorized user credentials from the environment.
+ TODO(developer) - See https://developers.google.com/identity
+ for guides on implementing OAuth2 for the application.
+ """
+ creds, _ = google.auth.default()
+ # pylint: disable=maybe-no-member
+ try:
+ service = build("slides", "v1", credentials=creds)
+ # Update the text style so that the first 5 characters are bolded
+ # and italicized, the next 5 are displayed in blue 14 pt Times
+ # New Roman font, and the next 5 are hyperlinked.
+ requests = [
+ {
+ "updateTextStyle": {
+ "objectId": shape_id,
+ "textRange": {
+ "type": "FIXED_RANGE",
+ "startIndex": 0,
+ "endIndex": 5,
+ },
+ "style": {"bold": True, "italic": True},
+ "fields": "bold,italic",
+ }
+ },
+ {
+ "updateTextStyle": {
+ "objectId": shape_id,
+ "textRange": {
+ "type": "FIXED_RANGE",
+ "startIndex": 5,
+ "endIndex": 10,
+ },
+ "style": {
+ "fontFamily": "Times New Roman",
+ "fontSize": {"magnitude": 14, "unit": "PT"},
+ "foregroundColor": {
+ "opaqueColor": {
+ "rgbColor": {
+ "blue": 1.0,
+ "green": 0.0,
+ "red": 0.0,
+ }
+ }
+ },
+ },
+ "fields": "foregroundColor,fontFamily,fontSize",
+ }
+ },
+ {
+ "updateTextStyle": {
+ "objectId": shape_id,
+ "textRange": {
+ "type": "FIXED_RANGE",
+ "startIndex": 10,
+ "endIndex": 15,
+ },
+ "style": {"link": {"url": "www.example.com"}},
+ "fields": "link",
+ }
+ },
+ ]
+
+ # Execute the requests.
+ body = {"requests": requests}
+ response = (
+ service.presentations()
+ .batchUpdate(presentationId=presentation_id, body=body)
+ .execute()
+ )
+ print(f"Updated the text style for shape with ID:{shape_id}")
+
+ return response
+ except HttpError as error:
+ print(f"An error occurred: {error}")
+ return error
+
+
+if __name__ == "__main__":
+ # Put the presentation_id, shape_id of slides
+ # to be submitted.
+ text_style_update(
+ "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4", "MyTextBox_9"
+ )
+# [END slides_text_style_update]
diff --git a/slides/snippets/test_slides_copy_presentation.py b/slides/snippets/test_slides_copy_presentation.py
new file mode 100644
index 00000000..c72c829c
--- /dev/null
+++ b/slides/snippets/test_slides_copy_presentation.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import slides_copy_presentation
+from base_test import BaseTest
+
+
+class TestCopyPresentation(BaseTest):
+ """Unit test for Copy presentation snippet"""
+
+ def test_copy_presentation(self):
+ """set title for copy presentation"""
+ presentation_id = self.create_test_presentation()
+ copy_id = slides_copy_presentation.copy_presentation(
+ presentation_id, "My Duplicate Presentation"
+ )
+ self.assertIsNotNone(copy_id)
+ self.delete_file_on_cleanup(copy_id)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_bulleted_text.py b/slides/snippets/test_slides_create_bulleted_text.py
new file mode 100644
index 00000000..885862e6
--- /dev/null
+++ b/slides/snippets/test_slides_create_bulleted_text.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_create_bulleted_text
+from base_test import BaseTest
+
+
+class TestCreateBulletedText(BaseTest):
+ """Unit test for create_bulleted_text snippet"""
+
+ def test_create_bulleted_text(self):
+ """create_bulleted_text function"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ box_id = self.create_test_textbox(presentation_id, page_id)
+ response = slides_create_bulleted_text.create_bulleted_text(
+ presentation_id, box_id
+ )
+ self.assertEqual(1, len(response.get("replies")), msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_image.py b/slides/snippets/test_slides_create_image.py
new file mode 100644
index 00000000..e8bb4237
--- /dev/null
+++ b/slides/snippets/test_slides_create_image.py
@@ -0,0 +1,35 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_create_image
+from base_test import BaseTest
+
+
+class TestCreateTextboxWithText(BaseTest):
+ """Unit test case for create_image snippet"""
+
+ def test_create_image(self):
+ """presentation id and page id for create image"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ response = slides_create_image.create_image(presentation_id, page_id)
+ self.assertEqual(1, len(response.get("replies")), msg=pformat(response))
+ image_id = response.get("replies")[0].get("createImage").get("objectId")
+ self.assertIsNotNone(image_id, msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_presentation.py b/slides/snippets/test_slides_create_presentation.py
new file mode 100644
index 00000000..06fd5f01
--- /dev/null
+++ b/slides/snippets/test_slides_create_presentation.py
@@ -0,0 +1,31 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import slides_create_presentation
+from base_test import BaseTest
+
+
+class TestCreatePresentation(BaseTest):
+ """Unit test for create presentation snippet"""
+
+ def test_create_presentation(self):
+ """Set title for create presentation"""
+ presentation = slides_create_presentation.create_presentation("Title")
+ self.assertIsNotNone(presentation)
+ self.delete_file_on_cleanup(presentation.get("presentationId"))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_sheets_chart.py b/slides/snippets/test_slides_create_sheets_chart.py
new file mode 100644
index 00000000..e9c1b8f3
--- /dev/null
+++ b/slides/snippets/test_slides_create_sheets_chart.py
@@ -0,0 +1,42 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_create_sheets_chart
+from base_test import BaseTest
+
+
+class TestCreateSheetsChart(BaseTest):
+ """Unit test for create_sheets_chart snippet"""
+
+ DATA_SPREADSHEET_ID = "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM"
+ CHART_ID = 1107320627
+
+ def test_create_sheets_chart(self):
+ """create_sheet chart method"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ response = slides_create_sheets_chart.create_sheets_chart(
+ presentation_id, page_id, self.DATA_SPREADSHEET_ID, self.CHART_ID
+ )
+ self.assertEqual(1, len(response.get("replies")), msg=pformat(response))
+ chart_id = (
+ response.get("replies")[0].get("createSheetsChart").get("objectId")
+ )
+ self.assertIsNotNone(chart_id, msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_slide.py b/slides/snippets/test_slides_create_slide.py
new file mode 100644
index 00000000..22c30eb1
--- /dev/null
+++ b/slides/snippets/test_slides_create_slide.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import slides_create_slide
+from base_test import BaseTest
+
+
+class TestCreateSlide(BaseTest):
+ """Unit test for create Slide snippet"""
+
+ def test_create_slide(self):
+ """pass presentation_id and page_id for creating the slides"""
+ presentation_id = self.create_test_presentation()
+ self.add_slides(presentation_id, 3)
+ page_id = "my_page_id"
+ response = slides_create_slide.create_slide(presentation_id, page_id)
+ self.assertEqual(
+ page_id,
+ response.get("replies")[0].get("createSlide").get("objectId"),
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_create_textbox_with_text.py b/slides/snippets/test_slides_create_textbox_with_text.py
new file mode 100644
index 00000000..36b0b70a
--- /dev/null
+++ b/slides/snippets/test_slides_create_textbox_with_text.py
@@ -0,0 +1,37 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_create_textbox_with_text
+from base_test import BaseTest
+
+
+class TestCreateTextboxWithText(BaseTest):
+ """Unit test for TestCreateTextboxWithText snippet"""
+
+ def test_create_textbox_with_text(self):
+ """Pass Presentation id and page id"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ response = slides_create_textbox_with_text.create_textbox_with_text(
+ presentation_id, page_id
+ )
+ self.assertEqual(2, len(response.get("replies")), msg=pformat(response))
+ box_id = response.get("replies")[0].get("createShape").get("objectId")
+ self.assertIsNotNone(box_id, msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_image_merging.py b/slides/snippets/test_slides_image_merging.py
new file mode 100644
index 00000000..844480ea
--- /dev/null
+++ b/slides/snippets/test_slides_image_merging.py
@@ -0,0 +1,48 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_image_merging
+from base_test import BaseTest
+
+
+class TestTextMerging(BaseTest):
+ """Unit test for text merging snippet"""
+
+ TEMPLATE_PRESENTATION_ID = "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4"
+ DATA_SPREADSHEET_ID = "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM"
+ IMAGE_URL = "https://picsum.photos/200"
+ CHART_ID = 1107320627
+ CUSTOMER_NAME = "Fake Customer"
+
+ def test_image_merging(self):
+ """image merging function"""
+ response = slides_image_merging.image_merging(
+ self.TEMPLATE_PRESENTATION_ID, self.IMAGE_URL, self.CUSTOMER_NAME
+ )
+ presentation_id = response.get("presentationId")
+ self.delete_file_on_cleanup(presentation_id)
+ self.assertIsNotNone(presentation_id, msg=pformat(response))
+ self.assertEqual(2, len(response.get("replies")), msg=pformat(response))
+ num_replacements = 0
+ for reply in response.get("replies"):
+ if isinstance(reply, int):
+ num_replacements += reply.get("replaceAllShapesWithImage").get(
+ "occurrencesChanged"
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_refresh_sheets_chart.py b/slides/snippets/test_slides_refresh_sheets_chart.py
new file mode 100644
index 00000000..9ecb7723
--- /dev/null
+++ b/slides/snippets/test_slides_refresh_sheets_chart.py
@@ -0,0 +1,41 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_refresh_sheets_chart
+from base_test import BaseTest
+
+
+class TestCreateSheetsChart(BaseTest):
+ """Unit test for refresh_sheets_chart snippet"""
+
+ DATA_SPREADSHEET_ID = "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM"
+ CHART_ID = 1107320627
+
+ def test_refresh_sheets_chart(self):
+ """refresh_sheets_chart method"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ chart_id = self.create_test_sheets_chart(
+ presentation_id, page_id, self.DATA_SPREADSHEET_ID, self.CHART_ID
+ )
+ response = slides_refresh_sheets_chart.refresh_sheets_chart(
+ presentation_id, chart_id
+ )
+ self.assertEqual(1, len(response.get("replies")), msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_simple_text_replace.py b/slides/snippets/test_slides_simple_text_replace.py
new file mode 100644
index 00000000..bbf854a2
--- /dev/null
+++ b/slides/snippets/test_slides_simple_text_replace.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_simple_text_replace
+from base_test import BaseTest
+
+
+class TestSimpleTextReplace(BaseTest):
+ """Unit test for SimpleTextReplace snippet"""
+
+ def test_simple_text_replace(self):
+ """test_simple_text_replace function"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ box_id = self.create_test_textbox(presentation_id, page_id)
+ response = slides_simple_text_replace.simple_text_replace(
+ presentation_id, box_id, "MY NEW TEXT"
+ )
+ self.assertEqual(2, len(response.get("replies")), msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_text_merging.py b/slides/snippets/test_slides_text_merging.py
new file mode 100644
index 00000000..f3f0ac54
--- /dev/null
+++ b/slides/snippets/test_slides_text_merging.py
@@ -0,0 +1,34 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+
+import slides_text_merging
+from base_test import BaseTest
+
+
+class TestTextMerging(BaseTest):
+ """Unit test for SimpleTextReplace snippet"""
+
+ TEMPLATE_PRESENTATION_ID = "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4"
+ DATA_SPREADSHEET_ID = "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM"
+
+ def test_text_merging(self):
+ """text_merging method"""
+ slides_text_merging.text_merging(
+ self.TEMPLATE_PRESENTATION_ID, self.DATA_SPREADSHEET_ID
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_slides_text_style_update.py b/slides/snippets/test_slides_text_style_update.py
new file mode 100644
index 00000000..1e7e8df0
--- /dev/null
+++ b/slides/snippets/test_slides_text_style_update.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2022 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from pprint import pformat
+
+import slides_text_style_update
+from base_test import BaseTest
+
+
+class TestTextStyleUpdate(BaseTest):
+ """Unit test for SimpleTextReplace snippet"""
+
+ def test_text_style_update(self):
+ """test_text_style_update function"""
+ presentation_id = self.create_test_presentation()
+ page_id = self.add_slides(presentation_id, 1, "BLANK")[0]
+ box_id = self.create_test_textbox(presentation_id, page_id)
+ response = slides_text_style_update.text_style_update(
+ presentation_id, box_id
+ )
+ self.assertEqual(3, len(response.get("replies")), msg=pformat(response))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/slides/snippets/test_snippets.py b/slides/snippets/test_snippets.py
deleted file mode 100644
index 9e9677fb..00000000
--- a/slides/snippets/test_snippets.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright 2018 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-from pprint import pformat
-
-from base_test import BaseTest
-from slides_snippets import SlidesSnippets
-
-
-class SnippetsTest(BaseTest):
- IMAGE_URL = 'https://www.google.com/images/' \
- 'branding/googlelogo/2x/googlelogo_color_272x92dp.png'
- TEMPLATE_PRESENTATION_ID = '1ElmXUX6de-b_OkH2iOK8PKS9FfQeln_Rx0aloIg6Rdc'
- DATA_SPREADSHEET_ID = '17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM'
- CHART_ID = 1107320627
- CUSTOMER_NAME = 'Fake Customer'
-
- @classmethod
- def setUpClass(cls):
- super(SnippetsTest, cls).setUpClass()
- cls.snippets = SlidesSnippets(
- cls.service,
- cls.drive_service,
- cls.sheets_service,
- cls.credentials)
-
- def test_create_presentation(self):
- presentation = self.snippets.create_presentation('Title')
- self.assertIsNotNone(presentation)
- self.delete_file_on_cleanup(presentation.get('presentationId'))
-
- def test_copy_presentation(self):
- presentation_id = self.create_test_presentation()
- copy_id = self.snippets.copy_presentation(
- presentation_id, 'My Duplicate Presentation')
- self.assertIsNotNone(copy_id)
- self.delete_file_on_cleanup(copy_id)
-
- def test_create_slide(self):
- presentation_id = self.create_test_presentation()
- self.add_slides(presentation_id, 3)
- page_id = 'my_page_id'
- response = self.snippets.create_slide(presentation_id, page_id)
- self.assertEqual(page_id,
- response.get('replies')[0].get('createSlide').get('objectId'))
-
- def test_create_textbox_with_text(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- response = self.snippets.create_textbox_with_text(
- presentation_id, page_id)
- self.assertEqual(2, len(response.get('replies')),
- msg=pformat(response))
- box_id = response.get('replies')[0].get('createShape').get('objectId')
- self.assertIsNotNone(box_id, msg=pformat(response))
-
- def test_create_image(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- response = self.snippets.create_image(presentation_id, page_id)
- self.assertEqual(1, len(response.get('replies')),
- msg=pformat(response))
- image_id = response.get('replies')[0].get(
- 'createImage').get('objectId')
- self.assertIsNotNone(image_id, msg=pformat(response))
-
- def test_text_merging(self):
- responses = self.snippets.text_merging(
- SnippetsTest.TEMPLATE_PRESENTATION_ID,
- SnippetsTest.DATA_SPREADSHEET_ID)
- for response in responses:
- presentation_id = response.get('presentationId')
- self.delete_file_on_cleanup(presentation_id)
- self.assertIsNotNone(presentation_id, msg=pformat(response))
- self.assertEqual(3, len(response.get('replies')),
- msg=pformat(response))
- num_replacements = 0
- for reply in response.get('replies'):
- num_replacements += reply.get('replaceAllText') \
- .get('occurrencesChanged')
- self.assertEqual(4, num_replacements, msg=pformat(reply))
-
- def test_image_merging(self):
- response = self.snippets.image_merging(
- SnippetsTest.TEMPLATE_PRESENTATION_ID,
- SnippetsTest.IMAGE_URL,
- SnippetsTest.CUSTOMER_NAME)
- presentation_id = response.get('presentationId')
- self.delete_file_on_cleanup(presentation_id)
- self.assertIsNotNone(presentation_id, msg=pformat(response))
- self.assertEqual(2, len(response.get('replies')),
- msg=pformat(response))
- num_replacements = 0
- for reply in response.get('replies'):
- num_replacements += reply.get('replaceAllShapesWithImage') \
- .get('occurrencesChanged')
- self.assertEqual(2, num_replacements)
-
- def test_simple_text_replace(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- box_id = self.create_test_textbox(presentation_id, page_id)
- response = self.snippets.simple_text_replace(
- presentation_id, box_id, 'MY NEW TEXT')
- self.assertEqual(2, len(response.get('replies')),
- msg=pformat(response))
-
- def test_text_style_update(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- box_id = self.create_test_textbox(presentation_id, page_id)
- response = self.snippets.text_style_update(presentation_id, box_id)
- self.assertEqual(3, len(response.get('replies')),
- msg=pformat(response))
-
- def test_create_bulleted_text(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- box_id = self.create_test_textbox(presentation_id, page_id)
- response = self.snippets.create_bulleted_text(presentation_id, box_id)
- self.assertEqual(1, len(response.get('replies')),
- msg=pformat(response))
-
- def test_create_sheets_chart(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- response = self.snippets.create_sheets_chart(presentation_id,
- page_id, SnippetsTest.DATA_SPREADSHEET_ID, SnippetsTest.CHART_ID)
- self.assertEqual(1, len(response.get('replies')),
- msg=pformat(response))
- chart_id = response.get('replies')[0].get('createSheetsChart') \
- .get('objectId')
- self.assertIsNotNone(chart_id, msg=pformat(response))
-
- def test_refresh_sheets_chart(self):
- presentation_id = self.create_test_presentation()
- page_id = self.add_slides(presentation_id, 1, 'BLANK')[0]
- chart_id = self.create_test_sheets_chart(presentation_id,
- page_id, SnippetsTest.DATA_SPREADSHEET_ID, SnippetsTest.CHART_ID)
- response = self.snippets.refresh_sheets_chart(
- presentation_id, chart_id)
- self.assertEqual(1, len(response.get('replies')),
- msg=pformat(response))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/solutions/webhook-chat-app/README.md b/solutions/webhook-chat-app/README.md
new file mode 100644
index 00000000..59643860
--- /dev/null
+++ b/solutions/webhook-chat-app/README.md
@@ -0,0 +1,4 @@
+# Google Chat App Webhook
+
+Please see related guide on how to
+[send messages to Google Chat with incoming webhooks](https://developers.google.com/workspace/chat/quickstart/webhooks).
diff --git a/solutions/webhook-chat-app/quickstart.py b/solutions/webhook-chat-app/quickstart.py
new file mode 100644
index 00000000..c7aba443
--- /dev/null
+++ b/solutions/webhook-chat-app/quickstart.py
@@ -0,0 +1,44 @@
+# 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 sample script for using an incoming webhook for Google Chat rooms.
+
+
+# [START chat_webhook]
+from json import dumps
+from httplib2 import Http
+
+# Copy the webhook URL from the Chat space where the webhook is registered.
+# The values for SPACE_ID, KEY, and TOKEN are set by Chat, and are included
+# when you copy the webhook URL.
+
+def main():
+ """Google Chat incoming webhook quickstart."""
+ url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN"
+ app_message = {
+ "text": "Hello from a Python script!"
+ }
+ message_headers = {"Content-Type": "application/json; charset=UTF-8"}
+ http_obj = Http()
+ response = http_obj.request(
+ uri=url,
+ method="POST",
+ headers=message_headers,
+ body=dumps(app_message),
+ )
+ print(response)
+
+
+if __name__ == "__main__":
+ main()
+# [END chat_webhook]
diff --git a/solutions/webhook-chat-app/requirements.txt b/solutions/webhook-chat-app/requirements.txt
new file mode 100644
index 00000000..e75eb880
--- /dev/null
+++ b/solutions/webhook-chat-app/requirements.txt
@@ -0,0 +1 @@
+httplib2>=0.17.0
diff --git a/solutions/webhook-chat-app/thread-reply.py b/solutions/webhook-chat-app/thread-reply.py
new file mode 100644
index 00000000..ba8b9aee
--- /dev/null
+++ b/solutions/webhook-chat-app/thread-reply.py
@@ -0,0 +1,52 @@
+# Copyright 2023 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.
+
+
+# [START chat_webhook_thread]
+from json import dumps
+from httplib2 import Http
+
+# Copy the webhook URL from the Chat space where the webhook is registered.
+# The values for SPACE_ID, KEY, and TOKEN are set by Chat, and are included
+# when you copy the webhook URL.
+#
+# Then, append messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD to the
+# webhook URL.
+
+
+def main():
+ """Google Chat incoming webhook that starts or replies to a message thread."""
+ url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
+ app_message = {
+ "text": "Hello from a Python script!",
+ # To start a thread, set threadKey to an arbitratry string.
+ # To reply to a thread, specify that thread's threadKey value.
+ "thread": {
+ "threadKey": "THREAD_KEY_VALUE"
+ },
+ }
+ message_headers = {"Content-Type": "application/json; charset=UTF-8"}
+ http_obj = Http()
+ response = http_obj.request(
+ uri=url,
+ method="POST",
+ headers=message_headers,
+ body=dumps(app_message),
+ )
+ print(response)
+
+
+if __name__ == "__main__":
+ main()
+# [END chat_webhook_thread]
diff --git a/tasks/quickstart/quickstart.py b/tasks/quickstart/quickstart.py
index ab0882b5..6f380c22 100644
--- a/tasks/quickstart/quickstart.py
+++ b/tasks/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START tasks_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,49 +22,50 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/tasks.readonly']
+SCOPES = ["https://www.googleapis.com/auth/tasks.readonly"]
def main():
- """Shows basic usage of the Tasks API.
- Prints the title and ID of the first 10 task lists.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
+ """Shows basic usage of the Tasks API.
+ Prints the title and ID of the first 10 task lists.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- try:
- service = build('tasks', 'v1', credentials=creds)
+ try:
+ service = build("tasks", "v1", credentials=creds)
- # Call the Tasks API
- results = service.tasklists().list(maxResults=10).execute()
- items = results.get('items', [])
+ # Call the Tasks API
+ results = service.tasklists().list(maxResults=10).execute()
+ items = results.get("items", [])
- if not items:
- print('No task lists found.')
- return
+ if not items:
+ print("No task lists found.")
+ return
- print('Task lists:')
- for item in items:
- print(u'{0} ({1})'.format(item['title'], item['id']))
- except HttpError as err:
- print(err)
+ print("Task lists:")
+ for item in items:
+ print(f"{item['title']} ({item['id']})")
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END tasks_quickstart]
diff --git a/vault/quickstart/quickstart.py b/vault/quickstart/quickstart.py
index cfd5f6ff..57dadd95 100644
--- a/vault/quickstart/quickstart.py
+++ b/vault/quickstart/quickstart.py
@@ -13,8 +13,6 @@
# limitations under the License.
# [START vault_quickstart]
-from __future__ import print_function
-
import os.path
from google.auth.transport.requests import Request
@@ -24,50 +22,50 @@
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
-SCOPES = ['https://www.googleapis.com/auth/ediscovery']
+SCOPES = ["https://www.googleapis.com/auth/ediscovery"]
def main():
- """Shows basic usage of the Vault API.
- Prints the names and IDs of the first 10 matters in Vault.
- """
- creds = None
- # The file token.json stores the user's access and refresh tokens, and is
- # created automatically when the authorization flow completes for the first
- # time.
- if os.path.exists('token.json'):
- creds = Credentials.from_authorized_user_file('token.json', SCOPES)
- # If there are no (valid) credentials available, let the user log in.
- if not creds or not creds.valid:
- if creds and creds.expired and creds.refresh_token:
- creds.refresh(Request())
- else:
- flow = InstalledAppFlow.from_client_secrets_file(
- 'credentials.json', SCOPES)
- creds = flow.run_local_server(port=0)
- # Save the credentials for the next run
- with open('token.json', 'w') as token:
- token.write(creds.to_json())
-
- try:
+ """Shows basic usage of the Vault API.
+ Prints the names and IDs of the first 10 matters in Vault.
+ """
+ creds = None
+ # The file token.json stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists("token.json"):
+ creds = Credentials.from_authorized_user_file("token.json", SCOPES)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ "credentials.json", SCOPES
+ )
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open("token.json", "w") as token:
+ token.write(creds.to_json())
- service = build('vault', 'v1', credentials=creds)
+ try:
+ service = build("vault", "v1", credentials=creds)
- # Call the Vault API
- results = service.matters().list(pageSize=10).execute()
- matters = results.get('matters', [])
+ # Call the Vault API
+ results = service.matters().list(pageSize=10).execute()
+ matters = results.get("matters", [])
- if not matters:
- print('No matters found.')
- return
+ if not matters:
+ print("No matters found.")
+ return
- print('Matters:')
- for matter in matters:
- print(u'{} ({})'.format(matter.get('name'), matter.get('id')))
- except HttpError as err:
- print(err)
+ print("Matters:")
+ for matter in matters:
+ print(f"{matter.get('name')} ({matter.get('id')})")
+ except HttpError as err:
+ print(err)
-if __name__ == '__main__':
- main()
+if __name__ == "__main__":
+ main()
# [END vault_quickstart]