aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-04-23 00:17:04 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-04-23 00:17:04 +0000
commitc1cd5cc298b6feffb41977ded6560094e4da40d9 (patch)
tree2a7502f1ce06ddd0d11041b6cccb532279e09f8b
parentc2884a2851ff96ec96ce37f10653c5bf2c28f6ff (diff)
parentc17cb82fa926603d201174cc8ec5bf87d3dd57d4 (diff)
downloadgoogle-api-python-client-c1cd5cc298b6feffb41977ded6560094e4da40d9.tar.gz
Upgrade python/google-api-python-client to v1.8.1 am: cf97e39f87 am: b4903596ac am: 4fd3d4c4ba am: c17cb82fa9
Change-Id: I804f78d0df0775e30e70b1d35cf4d160516ba1d2
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md22
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md7
-rw-r--r--.github/release-please.yml1
-rw-r--r--.gitignore2
-rwxr-xr-x.kokoro/build.sh32
-rw-r--r--.kokoro/common.cfg19
-rw-r--r--.kokoro/continuous/continuous.cfg2
-rw-r--r--.kokoro/presubmit/presubmit.cfg2
-rwxr-xr-x.kokoro/release.sh34
-rw-r--r--.kokoro/release/common.cfg64
-rw-r--r--.kokoro/release/release.cfg1
-rwxr-xr-x.kokoro/trampoline.sh17
-rw-r--r--.repo-metadata.json11
-rw-r--r--CHANGELOG.md (renamed from CHANGELOG)103
-rw-r--r--METADATA6
-rw-r--r--README.md4
-rw-r--r--googleapiclient/__init__.py2
-rw-r--r--googleapiclient/discovery.py23
-rw-r--r--googleapiclient/http.py28
-rw-r--r--googleapiclient/model.py7
-rw-r--r--noxfile.py78
-rw-r--r--renovate.json5
-rw-r--r--setup.py24
-rw-r--r--synth.metadata12
-rw-r--r--synth.py30
-rw-r--r--tests/test_discovery.py144
-rw-r--r--tests/test_http.py63
-rw-r--r--tests/test_json_model.py6
-rw-r--r--tox.ini24
29 files changed, 563 insertions, 210 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 3d44f3e4b..7d3526577 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -11,23 +11,33 @@ Thanks for stopping by to let us know something could be better!
Please run down the following list and make sure you've tried the usual "quick fixes":
- Search the issues already opened: https://github.com/googleapis/google-api-python-client/issues
- - If you have a question, post on Stackoverflow under the `google-api` tag.
- - If you are reporting an issue or requesting a feature for a G Suite API, please use their [public issue tracker](https://gsuite-developers.googleblog.com/2017/03/a-new-issue-tracker-for-g-suite.html)
+ - Search StackOverflow: https://stackoverflow.com/questions/tagged/google-cloud-platform+python
If you are still having issues, please be sure to include as much information as possible:
#### Environment details
- - OS:
- - Python version:
- - pip version:
- - `google-api-python-client` version:
+ - OS type and version:
+ - Python version: `python --version`
+ - pip version: `pip --version`
+ - `google-api-python-client` version: `pip show google-api-python-client`
#### Steps to reproduce
1. ?
2. ?
+#### Code example
+
+```python
+# example
+```
+
+#### Stack trace
+```
+# example
+```
+
Making sure to follow these steps will guarantee the quickest resolution possible.
Thanks!
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..24c6fa88f
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,7 @@
+Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
+- [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/google-api-python-client/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
+- [ ] Ensure the tests and linter pass
+- [ ] Code coverage does not decrease (if any source code was changed)
+- [ ] Appropriate docs were updated (if necessary)
+
+Fixes #<issue_number_goes_here> 🦕
diff --git a/.github/release-please.yml b/.github/release-please.yml
new file mode 100644
index 000000000..4507ad059
--- /dev/null
+++ b/.github/release-please.yml
@@ -0,0 +1 @@
+releaseType: python
diff --git a/.gitignore b/.gitignore
index cf2c4a698..1637b1d3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@ build/
dist/
# Test files
-.tox/
+.nox/
# Coverage files
.coverage
diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index e0c966b5a..ab8cebb4b 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -1,4 +1,17 @@
#!/bin/bash
+# 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
+#
+# 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.
set -eo pipefail
@@ -7,7 +20,20 @@ cd github/google-api-python-client
# Disable buffering, so that the logs stream through.
export PYTHONUNBUFFERED=1
-python3 -m pip install --upgrade tox
+# Debug: show build environment
+env | grep KOKORO
-# Run tests
-tox
+# Setup service account credentials.
+export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json
+
+# Setup project id.
+export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json")
+
+# Remove old nox
+python3.6 -m pip uninstall --yes --quiet nox-automation
+
+# Install nox
+python3.6 -m pip install --upgrade --quiet nox
+python3.6 -m nox --version
+
+python3.6 -m nox
diff --git a/.kokoro/common.cfg b/.kokoro/common.cfg
deleted file mode 100644
index c21dc6d4f..000000000
--- a/.kokoro/common.cfg
+++ /dev/null
@@ -1,19 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-# Download trampoline resources.
-gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
-
-# Use the trampoline script to run in docker.
-build_file: "google-api-python-client/.kokoro/trampoline.sh"
-
-# Configure the docker image for kokoro-trampoline.
-env_vars: {
- key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-kokoro-resources/python-multi"
-}
-
-# Tell the trampoline which build file to use.
-env_vars: {
- key: "TRAMPOLINE_BUILD_FILE"
- value: "github/google-api-python-client/.kokoro/build.sh"
-}
diff --git a/.kokoro/continuous/continuous.cfg b/.kokoro/continuous/continuous.cfg
index 18a4c3532..8f43917d9 100644
--- a/.kokoro/continuous/continuous.cfg
+++ b/.kokoro/continuous/continuous.cfg
@@ -1 +1 @@
-# Format: //devtools/kokoro/config/proto/build.proto
+# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file
diff --git a/.kokoro/presubmit/presubmit.cfg b/.kokoro/presubmit/presubmit.cfg
index 18a4c3532..8f43917d9 100644
--- a/.kokoro/presubmit/presubmit.cfg
+++ b/.kokoro/presubmit/presubmit.cfg
@@ -1 +1 @@
-# Format: //devtools/kokoro/config/proto/build.proto
+# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file
diff --git a/.kokoro/release.sh b/.kokoro/release.sh
new file mode 100755
index 000000000..b4756d089
--- /dev/null
+++ b/.kokoro/release.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!/bin/bash
+
+set -eo pipefail
+
+# Start the releasetool reporter
+python3 -m pip install gcp-releasetool
+python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script
+
+# Ensure that we have the latest versions of Twine, Wheel, and Setuptools.
+python3 -m pip install --upgrade twine wheel setuptools
+
+# Disable buffering, so that the logs stream through.
+export PYTHONUNBUFFERED=1
+
+# Move into the package, build the distribution and upload.
+TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google_cloud_pypi_password")
+cd github/google-api-python-client
+python3 setup.py sdist bdist_wheel
+twine upload --username gcloudpypi --password "${TWINE_PASSWORD}" dist/*
diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg
new file mode 100644
index 000000000..6a8864b88
--- /dev/null
+++ b/.kokoro/release/common.cfg
@@ -0,0 +1,64 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+# Build logs will be here
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.xml"
+ }
+}
+
+# Download trampoline resources.
+gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
+
+# Use the trampoline script to run in docker.
+build_file: "google-api-python-client/.kokoro/trampoline.sh"
+
+# Configure the docker image for kokoro-trampoline.
+env_vars: {
+ key: "TRAMPOLINE_IMAGE"
+ value: "gcr.io/cloud-devrel-kokoro-resources/python-multi"
+}
+env_vars: {
+ key: "TRAMPOLINE_BUILD_FILE"
+ value: "github/google-api-python-client/.kokoro/release.sh"
+}
+
+# Fetch the token needed for reporting release status to GitHub
+before_action {
+ fetch_keystore {
+ keystore_resource {
+ keystore_config_id: 73713
+ keyname: "yoshi-automation-github-key"
+ }
+ }
+}
+
+# Fetch PyPI password
+before_action {
+ fetch_keystore {
+ keystore_resource {
+ keystore_config_id: 73713
+ keyname: "google_cloud_pypi_password"
+ }
+ }
+}
+
+# Fetch magictoken to use with Magic Github Proxy
+before_action {
+ fetch_keystore {
+ keystore_resource {
+ keystore_config_id: 73713
+ keyname: "releasetool-magictoken"
+ }
+ }
+}
+
+# Fetch api key to use with Magic Github Proxy
+before_action {
+ fetch_keystore {
+ keystore_resource {
+ keystore_config_id: 73713
+ keyname: "magic-github-proxy-api-key"
+ }
+ }
+}
diff --git a/.kokoro/release/release.cfg b/.kokoro/release/release.cfg
new file mode 100644
index 000000000..8f43917d9
--- /dev/null
+++ b/.kokoro/release/release.cfg
@@ -0,0 +1 @@
+# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file
diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh
index 0efc3be38..e8c4251f3 100755
--- a/.kokoro/trampoline.sh
+++ b/.kokoro/trampoline.sh
@@ -12,13 +12,12 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+
set -eo pipefail
-# Always run the cleanup script, regardless of the success of bouncing into
-# the container.
-function cleanup() {
- chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
- ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
- echo "cleanup";
-}
-trap cleanup EXIT
-python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py"
+
+python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" || ret_code=$?
+
+chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
+${KOKORO_GFILE_DIR}/trampoline_cleanup.sh || true
+
+exit ${ret_code}
diff --git a/.repo-metadata.json b/.repo-metadata.json
new file mode 100644
index 000000000..1b810b0be
--- /dev/null
+++ b/.repo-metadata.json
@@ -0,0 +1,11 @@
+
+{
+ "name": "google-api-python-client",
+ "name_pretty": "Google API Python Client",
+ "client_documentation": "https://github.com/googleapis/google-api-python-client/tree/master/docs#google-api-client-library-for-python-docs",
+ "issue_tracker": "https://github.com/googleapis/google-api-python-client/issues",
+ "release_level": "ga",
+ "language": "python",
+ "repo": "googleapis/google-api-python-client",
+ "distribution_name": "google-api-python-client"
+ } \ No newline at end of file
diff --git a/CHANGELOG b/CHANGELOG.md
index 92b744e57..b0eb4fb1d 100644
--- a/CHANGELOG
+++ b/CHANGELOG.md
@@ -1,4 +1,25 @@
-v1.7.12
+# Changelog
+
+### [1.8.1](https://www.github.com/googleapis/google-api-python-client/compare/v1.8.0...v1.8.1) (2020-04-20)
+
+
+### Bug Fixes
+
+* Adding ConnectionError to retry mechanism ([#822](https://www.github.com/googleapis/google-api-python-client/issues/822)) ([c7516a2](https://www.github.com/googleapis/google-api-python-client/commit/c7516a2ea2c229479633690c109f8763dc0b30ed)), closes [googleapis#558](https://www.github.com/googleapis/googleapis/issues/558)
+* replace '-' in method names with '_' ([#863](https://www.github.com/googleapis/google-api-python-client/issues/863)) ([8ed729f](https://www.github.com/googleapis/google-api-python-client/commit/8ed729f1d868a8713ab442bf0bf59e77ba36afb6))
+
+### v1.8.0
+ Version 1.8.0
+
+ Release to support API endpoint override.
+
+ New Features
+ - Add api endpoint override. ([#829](https://github.com/googleapis/google-api-python-client/pull/829))
+
+ Implementation Changes
+ - Don't set http.redirect_codes if the attr doesn't exist and allow more httplib2 versions. ([#841](https://github.com/googleapis/google-api-python-client/pull/841))
+
+### v1.7.12
Version 1.7.12
Bugfix release
@@ -28,7 +49,7 @@ v1.7.12
- Blacken ([#772](https://github.com/googleapis/google-api-python-client/pull/722))
- Move kokoro configs ([#832](https://github.com/googleapis/google-api-python-client/pull/832))
-v1.7.11
+### v1.7.11
Version 1.7.11
Bugfix release
@@ -40,7 +61,7 @@ v1.7.11
- Fix typo in filename used in 'docs/auth.md' ([#736](https://github.com/googleapis/google-api-python-client/pull/736))
-v1.7.10
+### v1.7.10
Version 1.7.10
Bugfix release
@@ -62,21 +83,21 @@ v1.7.10
- tox.ini: Look for Python syntax errors and undefined names ([#721](https://github.com/googleapis/google-api-python-client/pull/721))
-v1.7.9
+### v1.7.9
Version 1.7.9
Bugfix release
- Remove Django Samples. ([#657](https://github.com/googleapis/google-api-python-client/pull/657))
- Call request_orig with kwargs ([#658](https://github.com/googleapis/google-api-python-client/pull/658))
-v1.7.8
+### v1.7.8
Version 1.7.8
Bugfix release
- Convert '$' in method name to '_' ([#616](https://github.com/googleapis/google-api-python-client/pull/616))
- Alias unitest2 import as unittest in test__auth.py ([#613](https://github.com/googleapis/google-api-python-client/pull/613))
-v1.7.7
+### v1.7.7
Version 1.7.7
Bugfix release
@@ -89,28 +110,28 @@ v1.7.7
- Add badges ([#455](https://github.com/google/google-api-python-client/pull/455))
-v1.7.6
+### v1.7.6
Version 1.7.6
Bugfix release
- Add client-side limit for batch requests (#585)
-v1.7.5
+### v1.7.5
Version 1.7.5
Bugfix release
- Fix the client to respect the passed in developerKey and credentials
-v1.7.4
+### v1.7.4
Version 1.7.4
Bugfix release
- Catch ServerNotFoundError to retry the request (#532)
-v1.7.3
+### v1.7.3
Version 1.7.3
Bugfix release
@@ -118,21 +139,21 @@ v1.7.3
- Make apiclient.sample_tools gracefully fail to import (#525).
-v1.7.2
+### v1.7.2
Version 1.7.2
Bugfix release
- Remove unnecessary check in apiclient/__ini__.py (#522).
-v1.7.1
+### v1.7.1
Version 1.7.1
Bugfix release
- Remove unnecessary check in setup.py (#518).
-v1.7.0
+### v1.7.0
Version 1.7.0
This release drops the hard requirement on oauth2client and installs
@@ -142,7 +163,7 @@ v1.7.0
- Drop oauth2client dependency (#499)
- Include tests in source distribution (#514)
-v1.6.7
+### v1.6.7
Version 1.6.7
Bugfix release
@@ -159,7 +180,7 @@ v1.6.7
- discovery.py: remove unused oauth2client import. (#492)
- Update README to reference GCP API client libraries. (#490)
-v1.6.6
+### v1.6.6
Version 1.6.6
Bugfix release
@@ -168,7 +189,7 @@ v1.6.6
- Increase the default media chunksize to 100MB. (#482)
- Remove unnecessary parsing of mime headers in HttpRequest.__init__ (#467)
-v1.6.5
+### v1.6.5
Version 1.6.5
Bugfix release
@@ -187,14 +208,14 @@ v1.6.5
- Handle variant error format gracefully. (#459)
- Avoid testing against Django >= 2.0.0 on Python 2. (#460)
-v1.6.4
+### v1.6.4
Version 1.6.4
Bugfix release
- Warn when google-auth credentials are used but google-auth-httplib2 isn't available. (#443)
-v1.6.3
+### v1.6.3
Version 1.6.3
Bugfix release
@@ -210,7 +231,7 @@ v1.6.3
- Don't treat httplib2.Credentials as oauth credentials. (#425)
- Various fixes to the Django sample. (#413)
-v1.6.2
+### v1.6.2
Version 1.6.2
Bugfix release
@@ -219,14 +240,14 @@ v1.6.2
when a developerKey was specified. (#347)
- Official support for Python 3.5 and 3.6. (#341)
-v1.6.1
+### v1.6.1
Version 1.6.1
Bugfix release
- Fixed a bug where using google-auth with scoped credentials would fail. (#328)
-v1.6.0
+### v1.6.0
Version 1.6.0
Release to drop support for Python 2.6 and add support for google-auth.
@@ -247,7 +268,7 @@ v1.6.0
- Fixed resumable upload failure when receiving a 308 response. (#312)
- Clarified the support versions of Python 3. (#316)
-v1.5.5
+### v1.5.5
Version 1.5.5
Bugfix release
@@ -257,7 +278,7 @@ v1.5.5
- Refresh all discovery docs, not just the preferred ones. (#298)
- Update minimum httplib2 dependency to >=0.9.2.
-v1.5.4
+### v1.5.4
Version 1.5.4
Bugfix release
@@ -267,14 +288,14 @@ v1.5.4
- Allow oauth2client 4.0.0, with the caveat that file-based discovery
caching is disabled.
-v1.5.3
+### v1.5.3
Version 1.5.3
Bugfix release
- Fixed import error with oauth2client >= 3.0.0. (#270)
-v1.5.2
+### v1.5.2
Version 1.5.2
Bugfix release
@@ -285,7 +306,7 @@ v1.5.2
- Obtain access token if necessary in BatchHttpRequest.execute(). (#232)
- Warn when running tests using HttpMock without having a cache. (#261)
-v1.5.1
+### v1.5.1
Version 1.5.1
Bugfix release
@@ -298,7 +319,7 @@ v1.5.1
- Use named loggers instead of the root logger. (#206)
- New search console example. (#212)
-v1.5.0
+### v1.5.0
Version 1.5.0
Release to support oauth2client >= 2.0.0.
@@ -309,22 +330,22 @@ v1.5.0
- Handle SSL errors with retries (#160)
- Fix incompatibility with oauth2client v2.0.0 (#182)
-v1.4.2
+### v1.4.2
Version 1.4.2
Add automatic caching for the discovery docs.
-v1.4.1
+### v1.4.1
Version 1.4.1
Add the googleapiclient.discovery.Resource.new_batch_http_request method.
-v1.4.0
+### v1.4.0
Version 1.4.0
Python 3 support.
-v1.3.2
+### v1.3.2
Version 1.3.2
Small bugfix release.
@@ -334,12 +355,12 @@ v1.3.2
- Better handling of `content-length` in media requests.
- Add support for methodPath entries containing colon.
-v1.3.1
+### v1.3.1
Version 1.3.1
Quick release for a fix around aliasing in v1.3.
-v1.3
+### v1.3
Version 1.3
Add support for the Google Application Default Credentials.
@@ -358,7 +379,7 @@ v1.3
setup.py attempts to detect this and prevents it. Simply remove
the previous version and reinstall to fix this.
-v1.2
+### v1.2
Version 1.2
The use of the gflags library is now deprecated, and is no longer a
@@ -384,7 +405,7 @@ v1.2
- Update AdExchange Buyer API examples to version v1.2.
-v1.1
+### v1.1
Version 1.1
Add PEM support to SignedJWTAssertionCredentials (used to only support
@@ -412,12 +433,12 @@ v1.1
- Ensure that dataWrapper feature is checked before using the 'data' value.
- HMAC verification does not use a constant time algorithm.
-v1.0
+### v1.0
Version 1.0
- Changes to the code for running tests and building releases.
-v1.0c3
+### v1.0c3
Version 1.0 Release Candidate 3
- In samples and oauth2 decorator, escape untrusted content before displaying it.
@@ -440,7 +461,7 @@ v1.0c3
- oauth2client support for URL-encoded format of exchange token response (e.g. Facebook)
- Build cleaner and easier to read docs for dynamic surfaces.
-v1.0c2
+### v1.0c2
Version 1.0 Release Candidate 2
- Parameter values of None should be treated as missing. Fixes issue #144.
@@ -448,7 +469,7 @@ v1.0c2
- Move all remaining samples over to client_secrets.json. Fixes issue #156.
- Make locked_file.py understand win32file primitives for better awesomeness.
-v1.0c1
+### v1.0c1
Version 1.0 Release Candidate 1
- Documentation for the library has switched to epydoc:
@@ -473,7 +494,7 @@ v1.0c1
* new analytics api samples. Reviewed here: http://codereview.appspot.com/5494058/
- Convert all inline samples to the Farm API for consistency.
-v1.0beta8
+### v1.0beta8
- Updated meda upload support.
- Many fixes for batch requests.
- Better handling for requests that don't require a body.
@@ -488,7 +509,7 @@ v1.0beta8
'body' parameter in your call. The solution is to remove the unneeded
body={} parameter.
-v1.0beta7
+### v1.0beta7
- Support for batch requests. http://code.google.com/p/google-api-python-client/wiki/Batch
- Support for media upload. http://code.google.com/p/google-api-python-client/wiki/MediaUpload
- Better handling for APIs that return something other than JSON.
diff --git a/METADATA b/METADATA
index 440c5d9cb..cd76b0c4d 100644
--- a/METADATA
+++ b/METADATA
@@ -9,10 +9,10 @@ third_party {
type: GIT
value: "https://github.com/google/google-api-python-client"
}
- version: "v1.7.12"
+ version: "v1.8.1"
last_upgrade_date {
year: 2020
- month: 3
- day: 11
+ month: 4
+ day: 20
}
}
diff --git a/README.md b/README.md
index ee38961d6..1ed3078f6 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,14 @@ These client libraries are officially supported by Google. However, the librari
See the [docs folder](docs/README.md) for more detailed instructions and additional documentation.
-## Google Cloud Platform / Google Ads
+## Other Google API libraries
For Google Cloud Platform APIs such as Datastore, Cloud Storage or Pub/Sub, we recommend using [Cloud Client Libraries for Python](https://github.com/GoogleCloudPlatform/google-cloud-python).
For Google Ads API, we recommend using [Google Ads API Client Library for Python](https://github.com/googleads/google-ads-python/).
+For Google Firebase Admin API, we recommend using [Firebase Admin Python SDK](https://github.com/firebase/firebase-admin-python).
+
## Installation
Install this library in a [virtualenv](https://virtualenv.pypa.io/en/latest/) using pip. virtualenv is a tool to
diff --git a/googleapiclient/__init__.py b/googleapiclient/__init__.py
index 140b946fb..c9218dd85 100644
--- a/googleapiclient/__init__.py
+++ b/googleapiclient/__init__.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "1.7.12"
-
# Set default logging handler to avoid "No handler found" warnings.
import logging
diff --git a/googleapiclient/discovery.py b/googleapiclient/discovery.py
index 87403b9e8..66d4927aa 100644
--- a/googleapiclient/discovery.py
+++ b/googleapiclient/discovery.py
@@ -46,6 +46,7 @@ import re
# Third-party imports
import httplib2
import uritemplate
+import google.api_core.client_options
# Local imports
from googleapiclient import _auth
@@ -130,10 +131,10 @@ def fix_method_name(name):
name: string, method name.
Returns:
- The name with '_' appended if the name is a reserved word and '$'
+ The name with '_' appended if the name is a reserved word and '$' and '-'
replaced with '_'.
"""
- name = name.replace("$", "_")
+ name = name.replace("$", "_").replace("-", "_")
if keyword.iskeyword(name) or name in RESERVED_WORDS:
return name + "_"
else:
@@ -176,6 +177,7 @@ def build(
credentials=None,
cache_discovery=True,
cache=None,
+ client_options=None,
):
"""Construct a Resource for interacting with an API.
@@ -202,6 +204,8 @@ def build(
cache_discovery: Boolean, whether or not to cache the discovery doc.
cache: googleapiclient.discovery_cache.base.CacheBase, an optional
cache object for the discovery documents.
+ client_options: Dictionary or google.api_core.client_options, Client options to set user
+ options on the client. API endpoint should be set through client_options.
Returns:
A Resource object with methods for interacting with the service.
@@ -228,6 +232,7 @@ def build(
model=model,
requestBuilder=requestBuilder,
credentials=credentials,
+ client_options=client_options
)
except HttpError as e:
if e.resp.status == http_client.NOT_FOUND:
@@ -304,6 +309,7 @@ def build_from_document(
model=None,
requestBuilder=HttpRequest,
credentials=None,
+ client_options=None
):
"""Create a Resource for interacting with an API.
@@ -328,6 +334,8 @@ def build_from_document(
credentials: oauth2client.Credentials or
google.auth.credentials.Credentials, credentials to be used for
authentication.
+ client_options: Dictionary or google.api_core.client_options, Client options to set user
+ options on the client. API endpoint should be set through client_options.
Returns:
A Resource object with methods for interacting with the service.
@@ -350,7 +358,16 @@ def build_from_document(
)
raise InvalidJsonError()
- base = urljoin(service["rootUrl"], service["servicePath"])
+ # If an API Endpoint is provided on client options, use that as the base URL
+ base = urljoin(service['rootUrl'], service["servicePath"])
+ if client_options:
+ if type(client_options) == dict:
+ client_options = google.api_core.client_options.from_dict(
+ client_options
+ )
+ if client_options.api_endpoint:
+ base = client_options.api_endpoint
+
schema = Schemas(service)
# If the http client is not specified, then we must construct an http client
diff --git a/googleapiclient/http.py b/googleapiclient/http.py
index 719664de1..41256668b 100644
--- a/googleapiclient/http.py
+++ b/googleapiclient/http.py
@@ -81,6 +81,11 @@ DEFAULT_HTTP_TIMEOUT_SEC = 60
_LEGACY_BATCH_URI = "https://www.googleapis.com/batch"
+if six.PY2:
+ # That's a builtin python3 exception, nonexistent in python2.
+ # Defined to None to avoid NameError while trying to catch it
+ ConnectionError = None
+
def _should_retry_response(resp_status, content):
"""Determines whether a response should be retried.
@@ -177,6 +182,10 @@ def _retry_request(
# It's important that this be before socket.error as it's a subclass
# socket.timeout has no errorcode
exception = socket_timeout
+ except ConnectionError as connection_error:
+ # Needs to be before socket.error as it's a subclass of
+ # OSError (socket.error)
+ exception = connection_error
except socket.error as socket_error:
# errno's contents differ by platform, so we have to match by name.
if socket.errno.errorcode.get(socket_error.errno) not in {
@@ -1751,16 +1760,18 @@ class HttpMockSequence(object):
connection_type=None,
):
resp, content = self._iterable.pop(0)
- if content == "echo_request_headers":
+ content = six.ensure_binary(content)
+
+ if content == b"echo_request_headers":
content = headers
- elif content == "echo_request_headers_as_json":
+ elif content == b"echo_request_headers_as_json":
content = json.dumps(headers)
- elif content == "echo_request_body":
+ elif content == b"echo_request_body":
if hasattr(body, "read"):
content = body.read()
else:
content = body
- elif content == "echo_request_uri":
+ elif content == b"echo_request_uri":
content = uri
if isinstance(content, six.text_type):
content = content.encode("utf-8")
@@ -1891,6 +1902,13 @@ def build_http():
# for Resumable Uploads rather than Permanent Redirects.
# This asks httplib2 to exclude 308s from the status codes
# it treats as redirects
- http.redirect_codes = http.redirect_codes - {308}
+ try:
+ http.redirect_codes = http.redirect_codes - {308}
+ except AttributeError:
+ # Apache Beam tests depend on this library and cannot
+ # currently upgrade their httplib2 version
+ # http.redirect_codes does not exist in previous versions
+ # of httplib2, so pass
+ pass
return http
diff --git a/googleapiclient/model.py b/googleapiclient/model.py
index 554056e3e..f58549c49 100644
--- a/googleapiclient/model.py
+++ b/googleapiclient/model.py
@@ -27,12 +27,13 @@ __author__ = "jcgregorio@google.com (Joe Gregorio)"
import json
import logging
import platform
+import pkg_resources
from six.moves.urllib.parse import urlencode
-from googleapiclient import __version__
from googleapiclient.errors import HttpError
+_LIBRARY_VERSION = pkg_resources.get_distribution("google-api-python-client").version
_PY_VERSION = platform.python_version()
LOGGER = logging.getLogger(__name__)
@@ -152,7 +153,7 @@ class BaseModel(Model):
else:
headers["x-goog-api-client"] = ""
headers["x-goog-api-client"] += "gdcl/%s gl-python/%s" % (
- __version__,
+ _LIBRARY_VERSION,
_PY_VERSION,
)
@@ -218,7 +219,7 @@ class BaseModel(Model):
return self.no_content_response
return self.deserialize(content)
else:
- LOGGER.debug("Content from bad request was: %s" % content)
+ LOGGER.debug("Content from bad request was: %r" % content)
raise HttpError(resp, content)
def serialize(self, body_value):
diff --git a/noxfile.py b/noxfile.py
new file mode 100644
index 000000000..438ff41c5
--- /dev/null
+++ b/noxfile.py
@@ -0,0 +1,78 @@
+
+# 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.
+
+import nox
+
+test_dependencies = [
+ "google-auth",
+ "google-auth-httplib2",
+ "mox",
+ "pyopenssl",
+ "pytest",
+ "pytest-cov",
+ "webtest",
+ "coverage",
+ "unittest2",
+ "mock",
+]
+
+
+@nox.session(python=["3.7"])
+def lint(session):
+ session.install("flake8")
+ session.run(
+ "flake8",
+ "googleapiclient",
+ "tests",
+ "--count",
+ "--select=E9,F63,F7,F82",
+ "--show-source",
+ "--statistics",
+ )
+
+
+@nox.parametrize(
+ "oauth2client",
+ [
+ "oauth2client<2dev",
+ "oauth2client>=2,<=3dev",
+ "oauth2client>=3,<=4dev",
+ "oauth2client>=4,<=5dev",
+ ],
+)
+@nox.session(python=["2.7", "3.5", "3.6", "3.7"])
+def unit(session, oauth2client):
+ session.install(*test_dependencies)
+ session.install(oauth2client)
+ if session.python < "3.0":
+ session.install("django<2.0.0")
+ else:
+ session.install("django>=2.0.0")
+
+ session.install('.')
+
+ # Run py.test against the unit tests.
+ session.run(
+ "py.test",
+ "--quiet",
+ "--cov=googleapiclient",
+ "--cov=tests",
+ "--cov-append",
+ "--cov-config=.coveragerc",
+ "--cov-report=",
+ "--cov-fail-under=85",
+ "tests",
+ *session.posargs,
+ ) \ No newline at end of file
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 000000000..f45d8f110
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,5 @@
+{
+ "extends": [
+ "config:base"
+ ]
+}
diff --git a/setup.py b/setup.py
index 617515bd1..60974fbdf 100644
--- a/setup.py
+++ b/setup.py
@@ -28,31 +28,40 @@ if (3, 1) <= sys.version_info < (3, 4):
print("google-api-python-client requires python3 version >= 3.4.", file=sys.stderr)
sys.exit(1)
+import io
+import os
from setuptools import setup
packages = ["apiclient", "googleapiclient", "googleapiclient/discovery_cache"]
install_requires = [
- "httplib2>=0.17.0,<1dev",
+ # NOTE: Apache Beam tests depend on this library and cannot
+ # currently upgrade their httplib2 version.
+ # Please see https://github.com/googleapis/google-api-python-client/pull/841
+ "httplib2>=0.9.2,<1dev",
"google-auth>=1.4.1",
"google-auth-httplib2>=0.0.3",
+ "google-api-core>=1.13.0,<2dev",
"six>=1.6.1,<2dev",
"uritemplate>=3.0.0,<4dev",
]
-long_desc = """The Google API Client for Python is a client library for
-accessing the Plus, Moderator, and many other Google APIs."""
+package_root = os.path.abspath(os.path.dirname(__file__))
-import googleapiclient
+readme_filename = os.path.join(package_root, "README.md")
+with io.open(readme_filename, encoding="utf-8") as readme_file:
+ readme = readme_file.read()
-version = googleapiclient.__version__
+version = "1.8.1"
setup(
name="google-api-python-client",
version=version,
description="Google API Client Library for Python",
- long_description=long_desc,
- author="Google Inc.",
+ long_description=readme,
+ long_description_content_type='text/markdown',
+ author="Google LLC",
+ author_email="googleapis-packages@google.com",
url="http://github.com/google/google-api-python-client/",
install_requires=install_requires,
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*",
@@ -64,7 +73,6 @@ setup(
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
diff --git a/synth.metadata b/synth.metadata
new file mode 100644
index 000000000..d06a0f15b
--- /dev/null
+++ b/synth.metadata
@@ -0,0 +1,12 @@
+{
+ "updateTime": "2020-03-30T20:47:31.469660Z",
+ "sources": [
+ {
+ "git": {
+ "name": "synthtool",
+ "remote": "https://github.com/googleapis/synthtool.git",
+ "sha": "f5e8c88d9870d8aa4eb43fa0b39f07e02bfbe4df"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/synth.py b/synth.py
new file mode 100644
index 000000000..017717db6
--- /dev/null
+++ b/synth.py
@@ -0,0 +1,30 @@
+# 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.
+
+import synthtool as s
+from synthtool import gcp
+
+common = gcp.CommonTemplates()
+
+# ----------------------------------------------------------------------------
+# Add templated files
+# ----------------------------------------------------------------------------
+templated_files = common.py_library()
+
+# Copy kokoro configs.
+# Docs are excluded as repo docs cannot currently be generated using sphinx.
+s.move(templated_files / '.kokoro', excludes=['**/docs/*', 'publish-docs.sh'])
+
+# Also move issue templates
+s.move(templated_files / '.github') \ No newline at end of file
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
index f85035ef4..6400f2147 100644
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -466,7 +466,7 @@ class DiscoveryFromDocument(unittest.TestCase):
plus = build_from_document(
discovery, base=base, credentials=self.MOCK_CREDENTIALS
)
- self.assertEquals("https://www.googleapis.com/plus/v1/", plus._baseUrl)
+ self.assertEqual("https://www.googleapis.com/plus/v1/", plus._baseUrl)
def test_building_with_optional_http_with_authorization(self):
discovery = open(datafile("plus.json")).read()
@@ -503,7 +503,7 @@ class DiscoveryFromDocument(unittest.TestCase):
plus = build_from_document(
discovery, base="https://www.googleapis.com/", http=http
)
- self.assertEquals(plus._http, http)
+ self.assertEqual(plus._http, http)
def test_building_with_developer_key_skips_adc(self):
discovery = open(datafile("plus.json")).read()
@@ -515,6 +515,25 @@ class DiscoveryFromDocument(unittest.TestCase):
# application default credentials were used.
self.assertNotIsInstance(plus._http, google_auth_httplib2.AuthorizedHttp)
+ def test_api_endpoint_override_from_client_options(self):
+ discovery = open(datafile("plus.json")).read()
+ api_endpoint = "https://foo.googleapis.com/"
+ options = google.api_core.client_options.ClientOptions(
+ api_endpoint=api_endpoint
+ )
+ plus = build_from_document(discovery, client_options=options)
+
+ self.assertEqual(plus._baseUrl, api_endpoint)
+
+ def test_api_endpoint_override_from_client_options_dict(self):
+ discovery = open(datafile("plus.json")).read()
+ api_endpoint = "https://foo.googleapis.com/"
+ plus = build_from_document(
+ discovery, client_options={"api_endpoint": api_endpoint}
+ )
+
+ self.assertEqual(plus._baseUrl, api_endpoint)
+
class DiscoveryFromHttp(unittest.TestCase):
def setUp(self):
@@ -588,6 +607,39 @@ class DiscoveryFromHttp(unittest.TestCase):
zoo = build("zoo", "v1", http=http, cache_discovery=False)
self.assertTrue(hasattr(zoo, "animals"))
+ def test_api_endpoint_override_from_client_options(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "404"}, "Not found"),
+ ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ]
+ )
+ api_endpoint = "https://foo.googleapis.com/"
+ options = google.api_core.client_options.ClientOptions(
+ api_endpoint=api_endpoint
+ )
+ zoo = build(
+ "zoo", "v1", http=http, cache_discovery=False, client_options=options
+ )
+ self.assertEqual(zoo._baseUrl, api_endpoint)
+
+ def test_api_endpoint_override_from_client_options_dict(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "404"}, "Not found"),
+ ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ]
+ )
+ api_endpoint = "https://foo.googleapis.com/"
+ zoo = build(
+ "zoo",
+ "v1",
+ http=http,
+ cache_discovery=False,
+ client_options={"api_endpoint": api_endpoint},
+ )
+ self.assertEqual(zoo._baseUrl, api_endpoint)
+
class DiscoveryFromAppEngineCache(unittest.TestCase):
def test_appengine_memcache(self):
@@ -928,8 +980,8 @@ class Discovery(unittest.TestCase):
self.http = HttpMock(datafile("zoo.json"), {"status": "200"})
zoo = build("zoo", "v1", http=self.http)
request = zoo.animals().crossbreed(media_body=datafile("small.png"))
- self.assertEquals("image/png", request.headers["content-type"])
- self.assertEquals(b"PNG", request.body[1:4])
+ self.assertEqual("image/png", request.headers["content-type"])
+ self.assertEqual(b"PNG", request.body[1:4])
def test_simple_media_raise_correct_exceptions(self):
self.http = HttpMock(datafile("zoo.json"), {"status": "200"})
@@ -952,8 +1004,8 @@ class Discovery(unittest.TestCase):
zoo = build("zoo", "v1", http=self.http)
request = zoo.animals().insert(media_body=datafile("small.png"))
- self.assertEquals("image/png", request.headers["content-type"])
- self.assertEquals(b"PNG", request.body[1:4])
+ self.assertEqual("image/png", request.headers["content-type"])
+ self.assertEqual(b"PNG", request.body[1:4])
assertUrisEqual(
self,
"https://www.googleapis.com/upload/zoo/v1/animals?uploadType=media&alt=json",
@@ -973,8 +1025,8 @@ class Discovery(unittest.TestCase):
request = zoo.animals().insert(
media_body=datafile("small-png"), media_mime_type="image/png"
)
- self.assertEquals("image/png", request.headers["content-type"])
- self.assertEquals(b"PNG", request.body[1:4])
+ self.assertEqual("image/png", request.headers["content-type"])
+ self.assertEqual(b"PNG", request.body[1:4])
assertUrisEqual(
self,
"https://www.googleapis.com/upload/zoo/v1/animals?uploadType=media&alt=json",
@@ -1045,13 +1097,13 @@ class Discovery(unittest.TestCase):
media_upload = MediaFileUpload(datafile("small.png"), resumable=True)
request = zoo.animals().insert(media_body=media_upload, body={})
self.assertTrue(request.headers["content-type"].startswith("application/json"))
- self.assertEquals('{"data": {}}', request.body)
- self.assertEquals(media_upload, request.resumable)
+ self.assertEqual('{"data": {}}', request.body)
+ self.assertEqual(media_upload, request.resumable)
- self.assertEquals("image/png", request.resumable.mimetype())
+ self.assertEqual("image/png", request.resumable.mimetype())
self.assertNotEquals(request.body, None)
- self.assertEquals(request.resumable_uri, None)
+ self.assertEqual(request.resumable_uri, None)
http = HttpMockSequence(
[
@@ -1078,32 +1130,32 @@ class Discovery(unittest.TestCase):
)
status, body = request.next_chunk(http=http)
- self.assertEquals(None, body)
+ self.assertEqual(None, body)
self.assertTrue(isinstance(status, MediaUploadProgress))
- self.assertEquals(0, status.resumable_progress)
+ self.assertEqual(0, status.resumable_progress)
# Two requests should have been made and the resumable_uri should have been
# updated for each one.
- self.assertEquals(request.resumable_uri, "http://upload.example.com/2")
- self.assertEquals(media_upload, request.resumable)
- self.assertEquals(0, request.resumable_progress)
+ self.assertEqual(request.resumable_uri, "http://upload.example.com/2")
+ self.assertEqual(media_upload, request.resumable)
+ self.assertEqual(0, request.resumable_progress)
# This next chuck call should upload the first chunk
status, body = request.next_chunk(http=http)
- self.assertEquals(request.resumable_uri, "http://upload.example.com/3")
- self.assertEquals(media_upload, request.resumable)
- self.assertEquals(13, request.resumable_progress)
+ self.assertEqual(request.resumable_uri, "http://upload.example.com/3")
+ self.assertEqual(media_upload, request.resumable)
+ self.assertEqual(13, request.resumable_progress)
# This call will upload the next chunk
status, body = request.next_chunk(http=http)
- self.assertEquals(request.resumable_uri, "http://upload.example.com/4")
- self.assertEquals(media_upload.size() - 1, request.resumable_progress)
- self.assertEquals('{"data": {}}', request.body)
+ self.assertEqual(request.resumable_uri, "http://upload.example.com/4")
+ self.assertEqual(media_upload.size() - 1, request.resumable_progress)
+ self.assertEqual('{"data": {}}', request.body)
# Final call to next_chunk should complete the upload.
status, body = request.next_chunk(http=http)
- self.assertEquals(body, {"foo": "bar"})
- self.assertEquals(status, None)
+ self.assertEqual(body, {"foo": "bar"})
+ self.assertEqual(status, None)
def test_resumable_media_good_upload(self):
"""Not a multipart upload."""
@@ -1112,12 +1164,12 @@ class Discovery(unittest.TestCase):
media_upload = MediaFileUpload(datafile("small.png"), resumable=True)
request = zoo.animals().insert(media_body=media_upload, body=None)
- self.assertEquals(media_upload, request.resumable)
+ self.assertEqual(media_upload, request.resumable)
- self.assertEquals("image/png", request.resumable.mimetype())
+ self.assertEqual("image/png", request.resumable.mimetype())
- self.assertEquals(request.body, None)
- self.assertEquals(request.resumable_uri, None)
+ self.assertEqual(request.body, None)
+ self.assertEqual(request.resumable_uri, None)
http = HttpMockSequence(
[
@@ -1143,26 +1195,26 @@ class Discovery(unittest.TestCase):
)
status, body = request.next_chunk(http=http)
- self.assertEquals(None, body)
+ self.assertEqual(None, body)
self.assertTrue(isinstance(status, MediaUploadProgress))
- self.assertEquals(13, status.resumable_progress)
+ self.assertEqual(13, status.resumable_progress)
# Two requests should have been made and the resumable_uri should have been
# updated for each one.
- self.assertEquals(request.resumable_uri, "http://upload.example.com/2")
+ self.assertEqual(request.resumable_uri, "http://upload.example.com/2")
- self.assertEquals(media_upload, request.resumable)
- self.assertEquals(13, request.resumable_progress)
+ self.assertEqual(media_upload, request.resumable)
+ self.assertEqual(13, request.resumable_progress)
status, body = request.next_chunk(http=http)
- self.assertEquals(request.resumable_uri, "http://upload.example.com/3")
- self.assertEquals(media_upload.size() - 1, request.resumable_progress)
- self.assertEquals(request.body, None)
+ self.assertEqual(request.resumable_uri, "http://upload.example.com/3")
+ self.assertEqual(media_upload.size() - 1, request.resumable_progress)
+ self.assertEqual(request.body, None)
# Final call to next_chunk should complete the upload.
status, body = request.next_chunk(http=http)
- self.assertEquals(body, {"foo": "bar"})
- self.assertEquals(status, None)
+ self.assertEqual(body, {"foo": "bar"})
+ self.assertEqual(status, None)
def test_resumable_media_good_upload_from_execute(self):
"""Not a multipart upload."""
@@ -1201,7 +1253,7 @@ class Discovery(unittest.TestCase):
)
body = request.execute(http=http)
- self.assertEquals(body, {"foo": "bar"})
+ self.assertEqual(body, {"foo": "bar"})
def test_resumable_media_fail_unknown_response_code_first_request(self):
"""Not a multipart upload."""
@@ -1247,7 +1299,7 @@ class Discovery(unittest.TestCase):
)
status, body = request.next_chunk(http=http)
- self.assertEquals(
+ self.assertEqual(
status.resumable_progress,
7,
"Should have first checked length and then tried to PUT more.",
@@ -1571,9 +1623,9 @@ class Discovery(unittest.TestCase):
media_upload = MediaFileUpload(datafile("empty"), resumable=True)
request = zoo.animals().insert(media_body=media_upload, body=None)
- self.assertEquals(media_upload, request.resumable)
- self.assertEquals(request.body, None)
- self.assertEquals(request.resumable_uri, None)
+ self.assertEqual(media_upload, request.resumable)
+ self.assertEqual(request.body, None)
+ self.assertEqual(request.resumable_uri, None)
http = HttpMockSequence(
[
@@ -1590,9 +1642,9 @@ class Discovery(unittest.TestCase):
)
status, body = request.next_chunk(http=http)
- self.assertEquals(None, body)
+ self.assertEqual(None, body)
self.assertTrue(isinstance(status, MediaUploadProgress))
- self.assertEquals(0, status.progress())
+ self.assertEqual(0, status.progress())
class Next(unittest.TestCase):
diff --git a/tests/test_http.py b/tests/test_http.py
index 2bf5060c0..2c0756e6c 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -132,32 +132,31 @@ class HttpMockWithErrors(object):
def request(self, *args, **kwargs):
if not self.num_errors:
return httplib2.Response(self.success_json), self.success_data
+ elif self.num_errors == 5 and PY3:
+ ex = ConnectionResetError # noqa: F821
+ elif self.num_errors == 4:
+ ex = httplib2.ServerNotFoundError()
+ elif self.num_errors == 3:
+ ex = socket.error()
+ ex.errno = socket.errno.EPIPE
+ elif self.num_errors == 2:
+ ex = ssl.SSLError()
else:
- self.num_errors -= 1
- if self.num_errors == 1: # initial == 2
- raise ssl.SSLError()
- if self.num_errors == 3: # initial == 4
- raise httplib2.ServerNotFoundError()
- else: # initial != 2,4
- if self.num_errors == 2:
- # first try a broken pipe error (#218)
- ex = socket.error()
- ex.errno = socket.errno.EPIPE
+ # Initialize the timeout error code to the platform's error code.
+ try:
+ # For Windows:
+ ex = socket.error()
+ ex.errno = socket.errno.WSAETIMEDOUT
+ except AttributeError:
+ # For Linux/Mac:
+ if PY3:
+ ex = socket.timeout()
else:
- # Initialize the timeout error code to the platform's error code.
- try:
- # For Windows:
- ex = socket.error()
- ex.errno = socket.errno.WSAETIMEDOUT
- except AttributeError:
- # For Linux/Mac:
- if PY3:
- ex = socket.timeout()
- else:
- ex = socket.error()
- ex.errno = socket.errno.ETIMEDOUT
- # Now raise the correct error.
- raise ex
+ ex = socket.error()
+ ex.errno = socket.errno.ETIMEDOUT
+
+ self.num_errors -= 1
+ raise ex
class HttpMockWithNonRetriableErrors(object):
@@ -562,14 +561,14 @@ class TestMediaIoBaseDownload(unittest.TestCase):
def test_media_io_base_download_retries_connection_errors(self):
self.request.http = HttpMockWithErrors(
- 4, {"status": "200", "content-range": "0-2/3"}, b"123"
+ 5, {"status": "200", "content-range": "0-2/3"}, b"123"
)
download = MediaIoBaseDownload(fd=self.fd, request=self.request, chunksize=3)
download._sleep = lambda _x: 0 # do nothing
download._rand = lambda: 10
- status, done = download.next_chunk(num_retries=4)
+ status, done = download.next_chunk(num_retries=5)
self.assertEqual(self.fd.getvalue(), b"123")
self.assertEqual(True, done)
@@ -899,13 +898,13 @@ class TestHttpRequest(unittest.TestCase):
def test_retry_connection_errors_non_resumable(self):
model = JsonModel()
request = HttpRequest(
- HttpMockWithErrors(4, {"status": "200"}, '{"foo": "bar"}'),
+ HttpMockWithErrors(5, {"status": "200"}, '{"foo": "bar"}'),
model.response,
u"https://www.example.com/json_api_endpoint",
)
request._sleep = lambda _x: 0 # do nothing
request._rand = lambda: 10
- response = request.execute(num_retries=4)
+ response = request.execute(num_retries=5)
self.assertEqual({u"foo": u"bar"}, response)
def test_retry_connection_errors_resumable(self):
@@ -918,7 +917,7 @@ class TestHttpRequest(unittest.TestCase):
request = HttpRequest(
HttpMockWithErrors(
- 4, {"status": "200", "location": "location"}, '{"foo": "bar"}'
+ 5, {"status": "200", "location": "location"}, '{"foo": "bar"}'
),
model.response,
u"https://www.example.com/file_upload",
@@ -927,7 +926,7 @@ class TestHttpRequest(unittest.TestCase):
)
request._sleep = lambda _x: 0 # do nothing
request._rand = lambda: 10
- response = request.execute(num_retries=4)
+ response = request.execute(num_retries=5)
self.assertEqual({u"foo": u"bar"}, response)
def test_retry(self):
@@ -1122,7 +1121,7 @@ class TestBatch(unittest.TestCase):
def test_id_to_from_content_id_header(self):
batch = BatchHttpRequest()
- self.assertEquals("12", batch._header_to_id(batch._id_to_header("12")))
+ self.assertEqual("12", batch._header_to_id(batch._id_to_header("12")))
def test_invalid_content_id_header(self):
batch = BatchHttpRequest()
@@ -1646,7 +1645,7 @@ class TestHttpBuild(unittest.TestCase):
def test_build_http_default_timeout_can_be_set_to_zero(self):
socket.setdefaulttimeout(0)
http = build_http()
- self.assertEquals(http.timeout, 0)
+ self.assertEqual(http.timeout, 0)
def test_build_http_default_308_is_excluded_as_redirect(self):
http = build_http()
diff --git a/tests/test_json_model.py b/tests/test_json_model.py
index 0064f3fd7..68578039e 100644
--- a/tests/test_json_model.py
+++ b/tests/test_json_model.py
@@ -26,17 +26,19 @@ __author__ = "jcgregorio@google.com (Joe Gregorio)"
import copy
import json
import os
+import pkg_resources
import platform
import unittest2 as unittest
import httplib2
import googleapiclient.model
-from googleapiclient import __version__
from googleapiclient.errors import HttpError
from googleapiclient.model import JsonModel
from six.moves.urllib.parse import parse_qs
+_LIBRARY_VERSION = pkg_resources.get_distribution("google-api-python-client").version
+
class Model(unittest.TestCase):
def test_json_no_body(self):
@@ -171,7 +173,7 @@ class Model(unittest.TestCase):
headers["x-goog-api-client"],
"gccl/1.23.4"
+ " gdcl/"
- + __version__
+ + _LIBRARY_VERSION
+ " gl-python/"
+ platform.python_version(),
)
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 1d9bc1391..000000000
--- a/tox.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[tox]
-envlist = py{27,34,35,36,37}-oauth2client{1,2,3,4}
-
-[testenv]
-deps =
- oauth2client1: oauth2client<2dev
- oauth2client2: oauth2client>=2,<=3dev
- oauth2client3: oauth2client>=3,<=4dev
- oauth2client4: oauth2client>=4,<=5dev
- google-auth
- google-auth-httplib2
- mox
- pyopenssl
- django<2.0.0; python_version < '3.0.0'
- django>=2.0.0; python_version > '3.0.0'
- flake8
- webtest
- nose
- coverage>=3.6,<3.99
- unittest2
- mock
-commands =
- flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- nosetests --with-coverage --cover-package=googleapiclient --nocapture --cover-erase --cover-tests --cover-branches --cover-min-percentage=85 []