From accff322b99ce24d2cab4ab6f1c8545054bcd9e8 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 10:45:42 -0700 Subject: [PATCH 1/8] Add dispatch and deserialize methods. This adds convenience methods used by client libraries produced by gapic-generator-python. --- api_core/google/api_core/gapic_v1/dispatch.py | 32 +++++++++++++++++++ api_core/google/api_core/operation.py | 12 +++++++ api_core/tests/unit/gapic/test_dispatch.py | 32 +++++++++++++++++++ api_core/tests/unit/test_operation.py | 8 +++++ 4 files changed, 84 insertions(+) create mode 100644 api_core/google/api_core/gapic_v1/dispatch.py create mode 100644 api_core/tests/unit/gapic/test_dispatch.py diff --git a/api_core/google/api_core/gapic_v1/dispatch.py b/api_core/google/api_core/gapic_v1/dispatch.py new file mode 100644 index 000000000000..2a231bff1e10 --- /dev/null +++ b/api_core/google/api_core/gapic_v1/dispatch.py @@ -0,0 +1,32 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools + + +def dispatch(func): + base_dispatcher = functools.singledispatch(func) + + # Define a wrapper function that works off args[1] instead of args[0]. + # This is needed because we are overloading *methods*, and their first + # argument is always `self`. + @functools.wraps(base_dispatcher) + def wrapper(*args, **kwargs): + return base_dispatcher.dispatch(args[1].__class__)(*args, **kwargs) + + # The register function is not changed, so let singledispatch do the work. + wrapper.register = base_dispatcher.register + + # Done; return the decorated method. + return wrapper diff --git a/api_core/google/api_core/operation.py b/api_core/google/api_core/operation.py index 51a7a9676b63..c76ac78ed163 100644 --- a/api_core/google/api_core/operation.py +++ b/api_core/google/api_core/operation.py @@ -94,6 +94,18 @@ def metadata(self): return protobuf_helpers.from_any_pb( self._metadata_type, self._operation.metadata) + @classmethod + def deserialize(self, payload): + """Deserialize a ``google.longrunning.Operation`` protocol buffer. + + Args: + payload (bytes): A serialized operation protocol buffer. + + Returns: + ~.operations_pb2.Operation: An Operation protobuf object. + """ + return operations_pb2.Operation.FromString(payload) + def _set_result_from_operation(self): """Set the result or exception from the operation if it is complete.""" # This must be done in a lock to prevent the polling thread diff --git a/api_core/tests/unit/gapic/test_dispatch.py b/api_core/tests/unit/gapic/test_dispatch.py new file mode 100644 index 000000000000..e9776dac83b7 --- /dev/null +++ b/api_core/tests/unit/gapic/test_dispatch.py @@ -0,0 +1,32 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.api_core.gapic_v1.dispatch import dispatch + + +def test_dispatch(): + class Foo(object): + @dispatch + def bar(self, number, letter): + return 'Brought by the letter {} and the number {}.'.format( + letter, number, + ) + + @bar.register(str) + def _bar_with_string(self, letter): + return self.bar(11, letter) + + foo = Foo() + assert foo.bar(8, 'L') == 'Brought by the letter L and the number 8.' + assert foo.bar('Z') == 'Brought by the letter Z and the number 11.' diff --git a/api_core/tests/unit/test_operation.py b/api_core/tests/unit/test_operation.py index 211fea6adc04..240eb867885c 100644 --- a/api_core/tests/unit/test_operation.py +++ b/api_core/tests/unit/test_operation.py @@ -221,3 +221,11 @@ def test_from_gapic(): assert future._metadata_type == struct_pb2.Struct assert future.operation.name == TEST_OPERATION_NAME assert future.done + + +def test_deserialize(): + op = make_operation_proto(name='foobarbaz') + serialized = op.SerializeToString() + deserialized_op = operation.Operation.deserialize(serialized) + assert op.name == deserialized_op.name + assert type(op) is type(deserialized_op) From 6411c7c75e49ddde3ae816a5572fcf520cd6f3bf Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 10:47:14 -0700 Subject: [PATCH 2/8] Bump version to 1.6.0a1 --- api_core/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api_core/setup.py b/api_core/setup.py index be0a35ebc188..666287430c44 100644 --- a/api_core/setup.py +++ b/api_core/setup.py @@ -22,12 +22,12 @@ name = 'google-api-core' description = 'Google API client core library' -version = '1.5.0' +version = '1.6.0a1' # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' # 'Development Status :: 5 - Production/Stable' -release_status = 'Development Status :: 5 - Production/Stable' +release_status = 'Development Status :: 3 - Alpha' dependencies = [ 'googleapis-common-protos<2.0dev,>=1.5.3', 'protobuf>=3.4.0', From 0ad32f2d838e26898db095ac5518510b3d2c6cdd Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 11:07:29 -0700 Subject: [PATCH 3/8] Mark test as Python 3 only. --- api_core/tests/unit/gapic/test_dispatch.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api_core/tests/unit/gapic/test_dispatch.py b/api_core/tests/unit/gapic/test_dispatch.py index e9776dac83b7..1778d749affe 100644 --- a/api_core/tests/unit/gapic/test_dispatch.py +++ b/api_core/tests/unit/gapic/test_dispatch.py @@ -14,7 +14,11 @@ from google.api_core.gapic_v1.dispatch import dispatch +import pytest +import six + +@pytest.mark.skipif(six.PY2, reason='dispatch only works on Python 3.') def test_dispatch(): class Foo(object): @dispatch From 3a3b4e59db309f0ae95baf408b30d05cb9996747 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 11:19:37 -0700 Subject: [PATCH 4/8] Fix import order. --- api_core/tests/unit/gapic/test_dispatch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api_core/tests/unit/gapic/test_dispatch.py b/api_core/tests/unit/gapic/test_dispatch.py index 1778d749affe..174008ae6544 100644 --- a/api_core/tests/unit/gapic/test_dispatch.py +++ b/api_core/tests/unit/gapic/test_dispatch.py @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from google.api_core.gapic_v1.dispatch import dispatch - import pytest import six +from google.api_core.gapic_v1.dispatch import dispatch + @pytest.mark.skipif(six.PY2, reason='dispatch only works on Python 3.') def test_dispatch(): From fdee8009b46078f012f5926602cb84ae648832ce Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 11:21:23 -0700 Subject: [PATCH 5/8] Address @theacodes feedback. --- api_core/google/api_core/gapic_v1/dispatch.py | 5 +++++ api_core/setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/api_core/google/api_core/gapic_v1/dispatch.py b/api_core/google/api_core/gapic_v1/dispatch.py index 2a231bff1e10..7b107a2b96eb 100644 --- a/api_core/google/api_core/gapic_v1/dispatch.py +++ b/api_core/google/api_core/gapic_v1/dispatch.py @@ -16,6 +16,11 @@ def dispatch(func): + """Return a decorated method that dispatches on the second argument. + + This is the equivalent of :meth:`functools.singledispatch`, but for + bound methods. + """ base_dispatcher = functools.singledispatch(func) # Define a wrapper function that works off args[1] instead of args[0]. diff --git a/api_core/setup.py b/api_core/setup.py index 666287430c44..45926bf7366e 100644 --- a/api_core/setup.py +++ b/api_core/setup.py @@ -22,7 +22,7 @@ name = 'google-api-core' description = 'Google API client core library' -version = '1.6.0a1' +version = '1.5.0' # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' From c0d348626c94c05ef32cf226fa68a58092b96075 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 12:30:49 -0700 Subject: [PATCH 6/8] Revert alpha designation. --- api_core/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api_core/setup.py b/api_core/setup.py index 45926bf7366e..be0a35ebc188 100644 --- a/api_core/setup.py +++ b/api_core/setup.py @@ -27,7 +27,7 @@ # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' # 'Development Status :: 5 - Production/Stable' -release_status = 'Development Status :: 3 - Alpha' +release_status = 'Development Status :: 5 - Production/Stable' dependencies = [ 'googleapis-common-protos<2.0dev,>=1.5.3', 'protobuf>=3.4.0', From 6e8c927d53f11822c6cc5866b1ecb3ed1f13cc83 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 15:45:42 -0700 Subject: [PATCH 7/8] Move dispatch to gapic_v2; alias remaining gapic_v1 modules. --- api_core/google/api_core/gapic_v2/__init__.py | 27 +++++++++++++++++++ .../{gapic_v1 => gapic_v2}/dispatch.py | 0 api_core/tests/unit/gapic/test_dispatch.py | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 api_core/google/api_core/gapic_v2/__init__.py rename api_core/google/api_core/{gapic_v1 => gapic_v2}/dispatch.py (100%) diff --git a/api_core/google/api_core/gapic_v2/__init__.py b/api_core/google/api_core/gapic_v2/__init__.py new file mode 100644 index 000000000000..4b9b573c595d --- /dev/null +++ b/api_core/google/api_core/gapic_v2/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.api_core.gapic_v1 import client_info +from google.api_core.gapic_v1 import config +from google.api_core.gapic_v2 import dispatch +from google.api_core.gapic_v1 import method +from google.api_core.gapic_v1 import routing_header + +__all__ = [ + 'client_info', + 'config', + 'dispatch', + 'method', + 'routing_header', +] diff --git a/api_core/google/api_core/gapic_v1/dispatch.py b/api_core/google/api_core/gapic_v2/dispatch.py similarity index 100% rename from api_core/google/api_core/gapic_v1/dispatch.py rename to api_core/google/api_core/gapic_v2/dispatch.py diff --git a/api_core/tests/unit/gapic/test_dispatch.py b/api_core/tests/unit/gapic/test_dispatch.py index 174008ae6544..aa7d87162c27 100644 --- a/api_core/tests/unit/gapic/test_dispatch.py +++ b/api_core/tests/unit/gapic/test_dispatch.py @@ -15,7 +15,7 @@ import pytest import six -from google.api_core.gapic_v1.dispatch import dispatch +from google.api_core.gapic_v2.dispatch import dispatch @pytest.mark.skipif(six.PY2, reason='dispatch only works on Python 3.') From 132830b49251df5914e2cc27c27315ecbd19c802 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Thu, 18 Oct 2018 16:09:10 -0700 Subject: [PATCH 8/8] Fix import order. --- api_core/google/api_core/gapic_v2/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api_core/google/api_core/gapic_v2/__init__.py b/api_core/google/api_core/gapic_v2/__init__.py index 4b9b573c595d..4a5cc70016c9 100644 --- a/api_core/google/api_core/gapic_v2/__init__.py +++ b/api_core/google/api_core/gapic_v2/__init__.py @@ -14,9 +14,9 @@ from google.api_core.gapic_v1 import client_info from google.api_core.gapic_v1 import config -from google.api_core.gapic_v2 import dispatch from google.api_core.gapic_v1 import method from google.api_core.gapic_v1 import routing_header +from google.api_core.gapic_v2 import dispatch __all__ = [ 'client_info',