Hello community,
here is the log from the commit of package python-google-api-core for
openSUSE:Factory checked in at 2018-09-13 12:12:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-api-core (Old)
and /work/SRC/openSUSE:Factory/.python-google-api-core.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-google-api-core"
Thu Sep 13 12:12:17 2018 rev:3 rq:635277 version:1.4.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-google-api-core/python-google-api-core.changes
2018-05-30 12:37:56.475160126 +0200
+++
/work/SRC/openSUSE:Factory/.python-google-api-core.new/python-google-api-core.changes
2018-09-13 12:14:01.398124007 +0200
@@ -1,0 +2,10 @@
+Wed Sep 12 08:06:43 UTC 2018 - Thomas Bechtold <[email protected]>
+
+- update to version 1.4.0
+ * Add support for gRPC connection management (available when using
+ optional grpc_gcp dependency) (#5553) (#5904)
+ * Update classifiers to drop Python 3.4 and add Python 3.7 (#5702)
+ * Add protobuf_helpers.field_mask to calculate a field mask from
+ two messages (#5320)
+
+-------------------------------------------------------------------
Old:
----
google-api-core-1.2.0.tar.gz
New:
----
google-api-core-1.4.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-google-api-core.spec ++++++
--- /var/tmp/diff_new_pack.z8CwgB/_old 2018-09-13 12:14:01.782123572 +0200
+++ /var/tmp/diff_new_pack.z8CwgB/_new 2018-09-13 12:14:01.782123572 +0200
@@ -12,13 +12,13 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-google-api-core
-Version: 1.2.0
+Version: 1.4.0
Release: 0
Summary: Google API client core library
License: Apache-2.0
++++++ google-api-core-1.2.0.tar.gz -> google-api-core-1.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-core-1.2.0/PKG-INFO
new/google-api-core-1.4.0/PKG-INFO
--- old/google-api-core-1.2.0/PKG-INFO 2018-05-25 23:28:52.000000000 +0200
+++ new/google-api-core-1.4.0/PKG-INFO 2018-09-11 20:19:45.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-api-core
-Version: 1.2.0
+Version: 1.4.0
Summary: Google API client core library
Home-page: https://github.com/GoogleCloudPlatform/google-cloud-python
Author: Google LLC
@@ -29,9 +29,10 @@
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet
Provides-Extra: grpc
+Provides-Extra: grpcio-gcp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google/api_core/gapic_v1/client_info.py
new/google-api-core-1.4.0/google/api_core/gapic_v1/client_info.py
--- old/google-api-core-1.2.0/google/api_core/gapic_v1/client_info.py
2018-04-25 19:05:26.000000000 +0200
+++ new/google-api-core-1.4.0/google/api_core/gapic_v1/client_info.py
2018-05-28 18:24:01.000000000 +0200
@@ -23,8 +23,13 @@
import pkg_resources
_PY_VERSION = platform.python_version()
-_GRPC_VERSION = pkg_resources.get_distribution('grpcio').version
_API_CORE_VERSION = pkg_resources.get_distribution('google-api-core').version
+
+try:
+ _GRPC_VERSION = pkg_resources.get_distribution('grpcio').version
+except pkg_resources.DistributionNotFound: # pragma: NO COVER
+ _GRPC_VERSION = None
+
METRICS_METADATA_KEY = 'x-goog-api-client'
@@ -38,7 +43,7 @@
Args:
python_version (str): The Python interpreter version, for example,
``'2.7.13'``.
- grpc_version (str): The gRPC library version.
+ grpc_version (Optional[str]): The gRPC library version.
api_core_version (str): The google-api-core library version.
gapic_version (Optional[str]): The sversion of gapic-generated client
library, if the library was generated by gapic.
@@ -66,15 +71,18 @@
# expects these items to be in specific locations.
ua = 'gl-python/{python_version} '
- if self.client_library_version is not None:
- ua += 'gccl/{client_library_version} '
+ if self.grpc_version is not None:
+ ua += 'grpc/{grpc_version} '
+
+ ua += 'gax/{api_core_version} '
if self.gapic_version is not None:
ua += 'gapic/{gapic_version} '
- ua += 'gax/{api_core_version} grpc/{grpc_version}'
+ if self.client_library_version is not None:
+ ua += 'gccl/{client_library_version} '
- return ua.format(**self.__dict__)
+ return ua.format(**self.__dict__).strip()
def to_grpc_metadata(self):
"""Returns the gRPC metadata for this client info."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google/api_core/gapic_v1/routing_header.py
new/google-api-core-1.4.0/google/api_core/gapic_v1/routing_header.py
--- old/google-api-core-1.2.0/google/api_core/gapic_v1/routing_header.py
2018-04-25 19:05:26.000000000 +0200
+++ new/google-api-core-1.4.0/google/api_core/gapic_v1/routing_header.py
2018-06-29 20:21:56.000000000 +0200
@@ -22,7 +22,7 @@
from six.moves.urllib.parse import urlencode
-ROUTING_METADATA_KEY = 'x-goog-header-params'
+ROUTING_METADATA_KEY = 'x-goog-request-params'
def to_routing_header(params):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google/api_core/grpc_helpers.py
new/google-api-core-1.4.0/google/api_core/grpc_helpers.py
--- old/google-api-core-1.2.0/google/api_core/grpc_helpers.py 2018-05-18
18:12:51.000000000 +0200
+++ new/google-api-core-1.4.0/google/api_core/grpc_helpers.py 2018-08-14
01:16:23.000000000 +0200
@@ -26,6 +26,11 @@
import google.auth.transport.grpc
import google.auth.transport.requests
+try:
+ import grpc_gcp
+ HAS_GRPC_GCP = True
+except ImportError:
+ HAS_GRPC_GCP = False
# The list of gRPC Callable interfaces that return iterators.
_STREAM_WRAP_CLASSES = (
@@ -149,7 +154,11 @@
return _wrap_unary_errors(callable_)
-def create_channel(target, credentials=None, scopes=None, **kwargs):
+def create_channel(target,
+ credentials=None,
+ scopes=None,
+ ssl_credentials=None,
+ **kwargs):
"""Create a secure channel with credentials.
Args:
@@ -160,8 +169,10 @@
scopes (Sequence[str]): A optional list of scopes needed for this
service. These are only used when credentials are not specified and
are passed to :func:`google.auth.default`.
+ ssl_credentials (grpc.ChannelCredentials): Optional SSL channel
+ credentials. This can be used to specify different certificates.
kwargs: Additional key-word args passed to
- :func:`google.auth.transport.grpc.secure_authorized_channel`.
+ :func:`grpc_gcp.secure_channel` or :func:`grpc.secure_channel`.
Returns:
grpc.Channel: The created channel.
@@ -174,8 +185,26 @@
request = google.auth.transport.requests.Request()
- return google.auth.transport.grpc.secure_authorized_channel(
- credentials, request, target, **kwargs)
+ # Create the metadata plugin for inserting the authorization header.
+ metadata_plugin = google.auth.transport.grpc.AuthMetadataPlugin(
+ credentials, request)
+
+ # Create a set of grpc.CallCredentials using the metadata plugin.
+ google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin)
+
+ if ssl_credentials is None:
+ ssl_credentials = grpc.ssl_channel_credentials()
+
+ # Combine the ssl credentials and the authorization credentials.
+ composite_credentials = grpc.composite_channel_credentials(
+ ssl_credentials, google_auth_credentials)
+
+ if HAS_GRPC_GCP:
+ # If grpc_gcp module is available use grpc_gcp.secure_channel,
+ # otherwise, use grpc.secure_channel to create grpc channel.
+ return grpc_gcp.secure_channel(target, composite_credentials, **kwargs)
+ else:
+ return grpc.secure_channel(target, composite_credentials, **kwargs)
_MethodCall = collections.namedtuple(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google/api_core/protobuf_helpers.py
new/google-api-core-1.4.0/google/api_core/protobuf_helpers.py
--- old/google-api-core-1.2.0/google/api_core/protobuf_helpers.py
2018-04-25 19:05:26.000000000 +0200
+++ new/google-api-core-1.4.0/google/api_core/protobuf_helpers.py
2018-07-25 21:43:09.000000000 +0200
@@ -15,11 +15,25 @@
"""Helpers for :mod:`protobuf`."""
import collections
+import copy
import inspect
-from google.protobuf.message import Message
+from google.protobuf import field_mask_pb2
+from google.protobuf import message
+from google.protobuf import wrappers_pb2
_SENTINEL = object()
+_WRAPPER_TYPES = (
+ wrappers_pb2.BoolValue,
+ wrappers_pb2.BytesValue,
+ wrappers_pb2.DoubleValue,
+ wrappers_pb2.FloatValue,
+ wrappers_pb2.Int32Value,
+ wrappers_pb2.Int64Value,
+ wrappers_pb2.StringValue,
+ wrappers_pb2.UInt32Value,
+ wrappers_pb2.UInt64Value,
+)
def from_any_pb(pb_type, any_pb):
@@ -73,13 +87,15 @@
module to find Message subclasses.
Returns:
- dict[str, Message]: A dictionary with the Message class names as
- keys, and the Message subclasses themselves as values.
+ dict[str, google.protobuf.message.Message]: A dictionary with the
+ Message class names as keys, and the Message subclasses themselves
+ as values.
"""
answer = collections.OrderedDict()
for name in dir(module):
candidate = getattr(module, name)
- if inspect.isclass(candidate) and issubclass(candidate, Message):
+ if (inspect.isclass(candidate) and
+ issubclass(candidate, message.Message)):
answer[name] = candidate
return answer
@@ -143,7 +159,7 @@
# Attempt to get the value from the two types of objects we know about.
# If we get something else, complain.
- if isinstance(msg_or_dict, Message):
+ if isinstance(msg_or_dict, message.Message):
answer = getattr(msg_or_dict, key, default)
elif isinstance(msg_or_dict, collections.Mapping):
answer = msg_or_dict.get(key, default)
@@ -186,7 +202,7 @@
# Assign the dictionary values to the protobuf message.
for item_key, item_value in value.items():
set(getattr(msg, key), item_key, item_value)
- elif isinstance(value, Message):
+ elif isinstance(value, message.Message):
getattr(msg, key).CopyFrom(value)
else:
setattr(msg, key, value)
@@ -205,7 +221,8 @@
TypeError: If ``msg_or_dict`` is not a Message or dictionary.
"""
# Sanity check: Is our target object valid?
- if not isinstance(msg_or_dict, (collections.MutableMapping, Message)):
+ if (not isinstance(msg_or_dict,
+ (collections.MutableMapping, message.Message))):
raise TypeError(
'set() expected a dict or protobuf message, got {!r}.'.format(
type(msg_or_dict)))
@@ -247,3 +264,84 @@
"""
if not get(msg_or_dict, key, default=None):
set(msg_or_dict, key, value)
+
+
+def field_mask(original, modified):
+ """Create a field mask by comparing two messages.
+
+ Args:
+ original (~google.protobuf.message.Message): the original message.
+ If set to None, this field will be interpretted as an empty
+ message.
+ modified (~google.protobuf.message.Message): the modified message.
+ If set to None, this field will be interpretted as an empty
+ message.
+
+ Returns:
+ google.protobuf.field_mask_pb2.FieldMask: field mask that contains
+ the list of field names that have different values between the two
+ messages. If the messages are equivalent, then the field mask is empty.
+
+ Raises:
+ ValueError: If the ``original`` or ``modified`` are not the same type.
+ """
+ if original is None and modified is None:
+ return field_mask_pb2.FieldMask()
+
+ if original is None and modified is not None:
+ original = copy.deepcopy(modified)
+ original.Clear()
+
+ if modified is None and original is not None:
+ modified = copy.deepcopy(original)
+ modified.Clear()
+
+ if type(original) != type(modified):
+ raise ValueError(
+ 'expected that both original and modified should be of the '
+ 'same type, received "{!r}" and "{!r}".'.
+ format(type(original), type(modified)))
+
+ return field_mask_pb2.FieldMask(
+ paths=_field_mask_helper(original, modified))
+
+
+def _field_mask_helper(original, modified, current=''):
+ answer = []
+
+ for name in original.DESCRIPTOR.fields_by_name:
+ field_path = _get_path(current, name)
+
+ original_val = getattr(original, name)
+ modified_val = getattr(modified, name)
+
+ if _is_message(original_val) or _is_message(modified_val):
+ if original_val != modified_val:
+ # Wrapper types do not need to include the .value part of the
+ # path.
+ if _is_wrapper(original_val) or _is_wrapper(modified_val):
+ answer.append(field_path)
+ elif not modified_val.ListFields():
+ answer.append(field_path)
+ else:
+ answer.extend(_field_mask_helper(original_val,
+ modified_val, field_path))
+ else:
+ if original_val != modified_val:
+ answer.append(field_path)
+
+ return answer
+
+
+def _get_path(current, name):
+ if not current:
+ return name
+ return '%s.%s' % (current, name)
+
+
+def _is_message(value):
+ return isinstance(value, message.Message)
+
+
+def _is_wrapper(value):
+ return type(value) in _WRAPPER_TYPES
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google_api_core.egg-info/PKG-INFO
new/google-api-core-1.4.0/google_api_core.egg-info/PKG-INFO
--- old/google-api-core-1.2.0/google_api_core.egg-info/PKG-INFO 2018-05-25
23:28:52.000000000 +0200
+++ new/google-api-core-1.4.0/google_api_core.egg-info/PKG-INFO 2018-09-11
20:19:45.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-api-core
-Version: 1.2.0
+Version: 1.4.0
Summary: Google API client core library
Home-page: https://github.com/GoogleCloudPlatform/google-cloud-python
Author: Google LLC
@@ -29,9 +29,10 @@
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet
Provides-Extra: grpc
+Provides-Extra: grpcio-gcp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/google_api_core.egg-info/requires.txt
new/google-api-core-1.4.0/google_api_core.egg-info/requires.txt
--- old/google-api-core-1.2.0/google_api_core.egg-info/requires.txt
2018-05-25 23:28:52.000000000 +0200
+++ new/google-api-core-1.4.0/google_api_core.egg-info/requires.txt
2018-09-11 20:19:45.000000000 +0200
@@ -11,3 +11,6 @@
[grpc]
grpcio>=1.8.2
+
+[grpcio-gcp]
+grpcio-gcp>=0.2.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-core-1.2.0/setup.py
new/google-api-core-1.4.0/setup.py
--- old/google-api-core-1.2.0/setup.py 2018-05-18 18:12:51.000000000 +0200
+++ new/google-api-core-1.4.0/setup.py 2018-09-11 19:52:42.000000000 +0200
@@ -22,7 +22,7 @@
name = 'google-api-core'
description = 'Google API client core library'
-version = '1.2.0'
+version = '1.4.0'
# Should be one of:
# 'Development Status :: 3 - Alpha'
# 'Development Status :: 4 - Beta'
@@ -39,7 +39,8 @@
'futures>=3.2.0;python_version<"3.2"'
]
extras = {
- 'grpc': 'grpcio>=1.8.2'
+ 'grpc': 'grpcio>=1.8.2',
+ 'grpcio-gcp': 'grpcio-gcp>=0.2.2'
}
@@ -80,9 +81,9 @@
'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',
'Operating System :: OS Independent',
'Topic :: Internet',
],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/tests/unit/gapic/test_client_info.py
new/google-api-core-1.4.0/tests/unit/gapic/test_client_info.py
--- old/google-api-core-1.2.0/tests/unit/gapic/test_client_info.py
2018-04-25 19:05:26.000000000 +0200
+++ new/google-api-core-1.4.0/tests/unit/gapic/test_client_info.py
2018-05-28 18:24:01.000000000 +0200
@@ -44,12 +44,13 @@
def test_to_user_agent_minimal():
info = client_info.ClientInfo(
python_version='1',
- grpc_version='2',
- api_core_version='3')
+ api_core_version='2',
+ grpc_version=None
+ )
user_agent = info.to_user_agent()
- assert user_agent == 'gl-python/1 gax/3 grpc/2'
+ assert user_agent == 'gl-python/1 gax/2'
def test_to_user_agent_full():
@@ -62,7 +63,7 @@
user_agent = info.to_user_agent()
- assert user_agent == 'gl-python/1 gccl/5 gapic/4 gax/3 grpc/2'
+ assert user_agent == 'gl-python/1 grpc/2 gax/3 gapic/4 gccl/5'
def test_to_grpc_metadata():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/tests/unit/test_grpc_helpers.py
new/google-api-core-1.4.0/tests/unit/test_grpc_helpers.py
--- old/google-api-core-1.2.0/tests/unit/test_grpc_helpers.py 2018-05-18
18:12:51.000000000 +0200
+++ new/google-api-core-1.4.0/tests/unit/test_grpc_helpers.py 2018-08-14
01:16:23.000000000 +0200
@@ -176,60 +176,157 @@
wrap_stream_errors.assert_called_once_with(callable_)
[email protected]('grpc.composite_channel_credentials')
@mock.patch(
'google.auth.default',
return_value=(mock.sentinel.credentials, mock.sentinel.projet))
[email protected]('google.auth.transport.grpc.secure_authorized_channel')
-def test_create_channel_implicit(secure_authorized_channel, default):
[email protected]('grpc.secure_channel')
+def test_create_channel_implicit(
+ grpc_secure_channel, default, composite_creds_call):
target = 'example.com:443'
+ composite_creds = composite_creds_call.return_value
channel = grpc_helpers.create_channel(target)
- assert channel is secure_authorized_channel.return_value
+ assert channel is grpc_secure_channel.return_value
default.assert_called_once_with(scopes=None)
- secure_authorized_channel.assert_called_once_with(
- mock.sentinel.credentials, mock.ANY, target)
+ if (grpc_helpers.HAS_GRPC_GCP):
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds, None)
+ else:
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds)
[email protected]('grpc.composite_channel_credentials')
@mock.patch(
'google.auth.default',
return_value=(mock.sentinel.credentials, mock.sentinel.projet))
[email protected]('google.auth.transport.grpc.secure_authorized_channel')
[email protected]('grpc.secure_channel')
+def test_create_channel_implicit_with_ssl_creds(
+ grpc_secure_channel, default, composite_creds_call):
+ target = 'example.com:443'
+
+ ssl_creds = grpc.ssl_channel_credentials()
+
+ grpc_helpers.create_channel(target, ssl_credentials=ssl_creds)
+
+ default.assert_called_once_with(scopes=None)
+ composite_creds_call.assert_called_once_with(ssl_creds, mock.ANY)
+ composite_creds = composite_creds_call.return_value
+ if (grpc_helpers.HAS_GRPC_GCP):
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds, None)
+ else:
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds)
+
+
[email protected]('grpc.composite_channel_credentials')
[email protected](
+ 'google.auth.default',
+ return_value=(mock.sentinel.credentials, mock.sentinel.projet))
[email protected]('grpc.secure_channel')
def test_create_channel_implicit_with_scopes(
- secure_authorized_channel, default):
+ grpc_secure_channel, default, composite_creds_call):
target = 'example.com:443'
+ composite_creds = composite_creds_call.return_value
channel = grpc_helpers.create_channel(target, scopes=['one', 'two'])
- assert channel is secure_authorized_channel.return_value
+ assert channel is grpc_secure_channel.return_value
default.assert_called_once_with(scopes=['one', 'two'])
+ if (grpc_helpers.HAS_GRPC_GCP):
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds, None)
+ else:
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds)
[email protected]('google.auth.transport.grpc.secure_authorized_channel')
-def test_create_channel_explicit(secure_authorized_channel):
[email protected]('grpc.composite_channel_credentials')
[email protected]('google.auth.credentials.with_scopes_if_required')
[email protected]('grpc.secure_channel')
+def test_create_channel_explicit(
+ grpc_secure_channel, auth_creds, composite_creds_call):
target = 'example.com:443'
+ composite_creds = composite_creds_call.return_value
channel = grpc_helpers.create_channel(
target, credentials=mock.sentinel.credentials)
- assert channel is secure_authorized_channel.return_value
- secure_authorized_channel.assert_called_once_with(
- mock.sentinel.credentials, mock.ANY, target)
+ auth_creds.assert_called_once_with(mock.sentinel.credentials, None)
+ assert channel is grpc_secure_channel.return_value
+ if (grpc_helpers.HAS_GRPC_GCP):
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds, None)
+ else:
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds)
[email protected]('google.auth.transport.grpc.secure_authorized_channel')
-def test_create_channel_explicit_scoped(unused_secure_authorized_channel):
[email protected]('grpc.composite_channel_credentials')
[email protected]('grpc.secure_channel')
+def test_create_channel_explicit_scoped(
+ grpc_secure_channel, composite_creds_call):
+ target = 'example.com:443'
scopes = ['1', '2']
+ composite_creds = composite_creds_call.return_value
+
+ credentials = mock.create_autospec(
+ google.auth.credentials.Scoped, instance=True)
+ credentials.requires_scopes = True
+
+ channel = grpc_helpers.create_channel(
+ target,
+ credentials=credentials,
+ scopes=scopes)
+
+ credentials.with_scopes.assert_called_once_with(scopes)
+ assert channel is grpc_secure_channel.return_value
+ if (grpc_helpers.HAS_GRPC_GCP):
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds, None)
+ else:
+ grpc_secure_channel.assert_called_once_with(
+ target, composite_creds)
+
+
[email protected](not grpc_helpers.HAS_GRPC_GCP,
+ reason='grpc_gcp module not available')
[email protected]('grpc_gcp.secure_channel')
+def test_create_channel_with_grpc_gcp(grpc_gcp_secure_channel):
+ target = 'example.com:443'
+ scopes = ['test_scope']
credentials = mock.create_autospec(
google.auth.credentials.Scoped, instance=True)
credentials.requires_scopes = True
grpc_helpers.create_channel(
- mock.sentinel.target,
+ target,
credentials=credentials,
scopes=scopes)
+ grpc_gcp_secure_channel.assert_called()
+ credentials.with_scopes.assert_called_once_with(scopes)
+
[email protected](grpc_helpers.HAS_GRPC_GCP,
+ reason='grpc_gcp module not available')
[email protected]('grpc.secure_channel')
+def test_create_channel_without_grpc_gcp(grpc_secure_channel):
+ target = 'example.com:443'
+ scopes = ['test_scope']
+
+ credentials = mock.create_autospec(
+ google.auth.credentials.Scoped, instance=True)
+ credentials.requires_scopes = True
+
+ grpc_helpers.create_channel(
+ target,
+ credentials=credentials,
+ scopes=scopes)
+ grpc_secure_channel.assert_called()
credentials.with_scopes.assert_called_once_with(scopes)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-core-1.2.0/tests/unit/test_protobuf_helpers.py
new/google-api-core-1.4.0/tests/unit/test_protobuf_helpers.py
--- old/google-api-core-1.2.0/tests/unit/test_protobuf_helpers.py
2018-04-25 19:05:26.000000000 +0200
+++ new/google-api-core-1.4.0/tests/unit/test_protobuf_helpers.py
2018-07-25 21:43:09.000000000 +0200
@@ -18,8 +18,13 @@
from google.api_core import protobuf_helpers
from google.longrunning import operations_pb2
from google.protobuf import any_pb2
+from google.protobuf import message
+from google.protobuf import source_context_pb2
+from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2
-from google.protobuf.message import Message
+from google.protobuf import type_pb2
+from google.protobuf import wrappers_pb2
+from google.type import color_pb2
from google.type import date_pb2
from google.type import timeofday_pb2
@@ -67,7 +72,7 @@
# Ensure that no non-Message objects were exported.
for value in answer.values():
- assert issubclass(value, Message)
+ assert issubclass(value, message.Message)
def test_get_dict_absent():
@@ -230,3 +235,225 @@
operation = operations_pb2.Operation(name='bar')
protobuf_helpers.setdefault(operation, 'name', 'foo')
assert operation.name == 'bar'
+
+
+def test_field_mask_invalid_args():
+ with pytest.raises(ValueError):
+ protobuf_helpers.field_mask('foo', any_pb2.Any())
+ with pytest.raises(ValueError):
+ protobuf_helpers.field_mask(any_pb2.Any(), 'bar')
+ with pytest.raises(ValueError):
+ protobuf_helpers.field_mask(any_pb2.Any(), operations_pb2.Operation())
+
+
+def test_field_mask_equal_values():
+ assert protobuf_helpers.field_mask(None, None).paths == []
+
+ original = struct_pb2.Value(number_value=1.0)
+ modified = struct_pb2.Value(number_value=1.0)
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ modified = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = struct_pb2.ListValue(
+ values=[struct_pb2.Value(number_value=1.0)])
+ modified = struct_pb2.ListValue(
+ values=[struct_pb2.Value(number_value=1.0)])
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = struct_pb2.Struct(
+ fields={'bar': struct_pb2.Value(number_value=1.0)})
+ modified = struct_pb2.Struct(
+ fields={'bar': struct_pb2.Value(number_value=1.0)})
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+
+def test_field_mask_zero_values():
+ # Singular Values
+ original = color_pb2.Color(red=0.0)
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = None
+ modified = color_pb2.Color(red=0.0)
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ # Repeated Values
+ original = struct_pb2.ListValue(values=[])
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = None
+ modified = struct_pb2.ListValue(values=[])
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ # Maps
+ original = struct_pb2.Struct(fields={})
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = None
+ modified = struct_pb2.Struct(fields={})
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ # Oneofs
+ original = struct_pb2.Value(number_value=0.0)
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+ original = None
+ modified = struct_pb2.Value(number_value=0.0)
+ assert protobuf_helpers.field_mask(original, modified).paths == []
+
+
+def test_field_mask_singular_field_diffs():
+ original = type_pb2.Type(name='name')
+ modified = type_pb2.Type()
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['name'])
+
+ original = type_pb2.Type(name='name')
+ modified = type_pb2.Type()
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['name'])
+
+ original = None
+ modified = type_pb2.Type(name='name')
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['name'])
+
+ original = type_pb2.Type(name='name')
+ modified = None
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['name'])
+
+
+def test_field_mask_message_diffs():
+ original = type_pb2.Type()
+ modified = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='name'))
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['source_context.file_name'])
+
+ original = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='name'))
+ modified = type_pb2.Type()
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['source_context'])
+
+ original = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='name'))
+ modified = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='other_name'))
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['source_context.file_name'])
+
+ original = None
+ modified = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='name'))
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['source_context.file_name'])
+
+ original = type_pb2.Type(source_context=source_context_pb2.SourceContext(
+ file_name='name'))
+ modified = None
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['source_context'])
+
+
+def test_field_mask_wrapper_type_diffs():
+ original = color_pb2.Color()
+ modified = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ assert protobuf_helpers.field_mask(original, modified).paths == ['alpha']
+
+ original = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ modified = color_pb2.Color()
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['alpha'])
+
+ original = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ modified = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=2.0))
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['alpha'])
+
+ original = None
+ modified = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=2.0))
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['alpha'])
+
+ original = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ modified = None
+ assert (protobuf_helpers.field_mask(original, modified).paths ==
+ ['alpha'])
+
+
+def test_field_mask_repeated_diffs():
+ original = struct_pb2.ListValue()
+ modified = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=1.0),
+ struct_pb2.Value(number_value=2.0)])
+ assert protobuf_helpers.field_mask(original, modified).paths == ['values']
+
+ original = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=1.0),
+ struct_pb2.Value(number_value=2.0)])
+ modified = struct_pb2.ListValue()
+ assert protobuf_helpers.field_mask(original, modified).paths == ['values']
+
+ original = None
+ modified = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=1.0),
+ struct_pb2.Value(number_value=2.0)])
+ assert protobuf_helpers.field_mask(original, modified).paths == ['values']
+
+ original = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=1.0),
+ struct_pb2.Value(number_value=2.0)])
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == ['values']
+
+ original = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=1.0),
+ struct_pb2.Value(number_value=2.0)])
+ modified = struct_pb2.ListValue(values=[struct_pb2.Value(number_value=2.0),
+ struct_pb2.Value(number_value=1.0)])
+ assert protobuf_helpers.field_mask(original, modified).paths == ['values']
+
+
+def test_field_mask_map_diffs():
+ original = struct_pb2.Struct()
+ modified = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+ original = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ modified = struct_pb2.Struct()
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+ original = None
+ modified = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+ original = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ modified = None
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+ original = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ modified = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=2.0)})
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+ original = struct_pb2.Struct(
+ fields={'foo': struct_pb2.Value(number_value=1.0)})
+ modified = struct_pb2.Struct(
+ fields={'bar': struct_pb2.Value(number_value=1.0)})
+ assert protobuf_helpers.field_mask(original, modified).paths == ['fields']
+
+
+def test_field_mask_different_level_diffs():
+ original = color_pb2.Color(alpha=wrappers_pb2.FloatValue(value=1.0))
+ modified = color_pb2.Color(
+ alpha=wrappers_pb2.FloatValue(value=2.0), red=1.0)
+ assert (sorted(protobuf_helpers.field_mask(original, modified).paths) ==
+ ['alpha', 'red'])