Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add RequestOptions proto; add optimizer_statistics_package to QueryOptions #288

Merged
merged 10 commits into from
Apr 6, 2021
44 changes: 22 additions & 22 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ limitations under the License.

# 2.0.0 Migration Guide

The 2.0 release of the `google-cloud-spanner` client is a significant update based on a
The 2.0 release of the `google-cloud-spanner` client is a significant update based on a
[next-gen code generator](https://github.com/googleapis/gapic-generator-python).
It drops support for Python versions below 3.6.
It drops support for Python versions below 3.6.

The handwritten client surfaces have minor changes which may require minimal updates to existing user code.

The generated client surfaces have substantial interface changes. Existing user code which uses these surfaces directly
The generated client surfaces have substantial interface changes. Existing user code which uses these surfaces directly
will require significant updates to use this version.

This document describes the changes that have been made, and what you need to do to update your usage.
Expand Down Expand Up @@ -89,7 +89,7 @@ for database_pb in instance.list_databases():
> **WARNING**: Breaking change

The library now handles pages for the user. Previously, the library would return a page generator which required a user
to then iterate over each page to get the resource. Now, the library handles iterating over the pages and only returns
to then iterate over each page to get the resource. Now, the library handles iterating over the pages and only returns
the resource protos.

**Before:**
Expand Down Expand Up @@ -176,14 +176,14 @@ for database_pb in instance.list_databases():

Methods expect request objects. We provide scripts that will convert most common use cases.

* Install the library
* Install the library with `libcst`.

```py
python3 -m pip install google-cloud-spanner
python3 -m pip install google-cloud-spanner[libcst]
```

* The scripts `fixup_spanner_v1_keywords.py`, `fixup_spanner_admin_database_v1_keywords.py`, and
`fixup_spanner_admin_instance_v1_keywords.py` are shipped with the library. They expect an input directory (with the
`fixup_spanner_admin_instance_v1_keywords.py` are shipped with the library. They expect an input directory (with the
code to convert) and an empty destination directory.

```sh
Expand All @@ -194,10 +194,10 @@ $ fixup_spanner_v1_keywords.py --input-directory .samples/ --output-directory sa
>the handwritten surfaces e.g. `client.list_instances()`

#### More details

In `google-cloud-spanner<2.0.0`, parameters required by the API were positional parameters and optional parameters were
keyword parameters.

**Before:**
```py
def list_instances(
Expand All @@ -210,14 +210,14 @@ def list_instances(
metadata=None,
):
```
In the 2.0.0 release, all methods have a single positional parameter `request`. Method docstrings indicate whether a

In the 2.0.0 release, all methods have a single positional parameter `request`. Method docstrings indicate whether a
parameter is required or optional.
Some methods have additional keyword only parameters. The available parameters depend on the

Some methods have additional keyword only parameters. The available parameters depend on the
[`google.api.method_signature` annotation](https://github.com/googleapis/googleapis/blob/master/google/spanner/admin/instance/v1/spanner_instance_admin.proto#L86) specified by the API producer.


**After:**
```py
def list_instances(
Expand All @@ -230,30 +230,30 @@ def list_instances(
metadata: Sequence[Tuple[str, str]] = (),
) -> pagers.ListInstancesPager:
```

> **NOTE:** The `request` parameter and flattened keyword parameters for the API are mutually exclusive.
> Passing both will result in an error.


Both of these calls are valid:

```py
response = client.list_instances(
request={
"parent": project_name,
}
)
```

```py
response = client.execute_sql(
parent=project_name,
)
```

This call is invalid because it mixes `request` with a keyword argument `parent`. Executing this code
will result in an error.

```py
response = client.execute_sql(
request={},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ message RestoreDatabaseRequest {
// to. If this field is not specified, the restored database will use the same
// encryption configuration as the backup by default, namely
// [encryption_type][google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.encryption_type]
// = `USE_CONFIG_DEFAULT_OR_DATABASE_ENCRYPTION`.
// = `USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION`.
RestoreDatabaseEncryptionConfig encryption_config = 4
[(google.api.field_behavior) = OPTIONAL];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,36 @@ class DatabaseAdminAsyncClient:
DatabaseAdminClient.parse_common_location_path
)

from_service_account_info = DatabaseAdminClient.from_service_account_info
from_service_account_file = DatabaseAdminClient.from_service_account_file
@classmethod
def from_service_account_info(cls, info: dict, *args, **kwargs):
"""Creates an instance of this client using the provided credentials info.

Args:
info (dict): The service account private key info.
args: Additional arguments to pass to the constructor.
kwargs: Additional arguments to pass to the constructor.

Returns:
DatabaseAdminAsyncClient: The constructed client.
"""
return DatabaseAdminClient.from_service_account_info.__func__(DatabaseAdminAsyncClient, info, *args, **kwargs) # type: ignore

@classmethod
def from_service_account_file(cls, filename: str, *args, **kwargs):
"""Creates an instance of this client using the provided credentials
file.

Args:
filename (str): The path to the service account private key json
file.
args: Additional arguments to pass to the constructor.
kwargs: Additional arguments to pass to the constructor.

Returns:
DatabaseAdminAsyncClient: The constructed client.
"""
return DatabaseAdminClient.from_service_account_file.__func__(DatabaseAdminAsyncClient, filename, *args, **kwargs) # type: ignore

from_service_account_json = from_service_account_file

@property
Expand Down Expand Up @@ -236,6 +264,7 @@ async def list_databases(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -431,6 +460,7 @@ async def get_database(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -559,6 +589,7 @@ async def update_database_ddl(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -642,6 +673,7 @@ async def drop_database(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -726,6 +758,7 @@ async def get_database_ddl(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1007,6 +1040,7 @@ async def get_iam_policy(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=30.0,
),
default_timeout=30.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1302,6 +1336,7 @@ async def get_backup(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1402,6 +1437,7 @@ async def update_backup(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1481,6 +1517,7 @@ async def delete_backup(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1566,6 +1603,7 @@ async def list_backups(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1795,6 +1833,7 @@ async def list_database_operations(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down Expand Up @@ -1897,6 +1936,7 @@ async def list_backup_operations(
predicate=retries.if_exception_type(
exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
),
deadline=3600.0,
),
default_timeout=3600.0,
client_info=DEFAULT_CLIENT_INFO,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1082,11 +1082,10 @@ def set_iam_policy(
"the individual field arguments should be set."
)

# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
if isinstance(request, dict):
# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
request = iam_policy.SetIamPolicyRequest(**request)

elif not request:
# Null request, just make one.
request = iam_policy.SetIamPolicyRequest()
Expand Down Expand Up @@ -1219,11 +1218,10 @@ def get_iam_policy(
"the individual field arguments should be set."
)

# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
if isinstance(request, dict):
# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
request = iam_policy.GetIamPolicyRequest(**request)

elif not request:
# Null request, just make one.
request = iam_policy.GetIamPolicyRequest()
Expand Down Expand Up @@ -1311,11 +1309,10 @@ def test_iam_permissions(
"the individual field arguments should be set."
)

# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
if isinstance(request, dict):
# The request isn't a proto-plus wrapped type,
# so it must be constructed via keyword expansion.
request = iam_policy.TestIamPermissionsRequest(**request)

elif not request:
# Null request, just make one.
request = iam_policy.TestIamPermissionsRequest()
Expand Down
Loading