Add methods to api_core used by new autogenerator. (#6267)

* Add dispatch and deserialize methods.

This adds convenience methods used by client libraries produced by
gapic-generator-python.
* Mark test as Python 3 only.

* Fix import order.

* Address @theacodes feedback.

* Move dispatch to gapic_v2; alias remaining gapic_v1 modules.

* Fix import order.
diff --git a/google/api_core/gapic_v2/__init__.py b/google/api_core/gapic_v2/__init__.py
new file mode 100644
index 0000000..4a5cc70
--- /dev/null
+++ b/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_v1 import method
+from google.api_core.gapic_v1 import routing_header
+from google.api_core.gapic_v2 import dispatch
+
+__all__ = [
+    'client_info',
+    'config',
+    'dispatch',
+    'method',
+    'routing_header',
+]
diff --git a/google/api_core/gapic_v2/dispatch.py b/google/api_core/gapic_v2/dispatch.py
new file mode 100644
index 0000000..7b107a2
--- /dev/null
+++ b/google/api_core/gapic_v2/dispatch.py
@@ -0,0 +1,37 @@
+# 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):
+    """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].
+    # 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/google/api_core/operation.py b/google/api_core/operation.py
index 51a7a96..c76ac78 100644
--- a/google/api_core/operation.py
+++ b/google/api_core/operation.py
@@ -94,6 +94,18 @@
         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/tests/unit/gapic/test_dispatch.py b/tests/unit/gapic/test_dispatch.py
new file mode 100644
index 0000000..aa7d871
--- /dev/null
+++ b/tests/unit/gapic/test_dispatch.py
@@ -0,0 +1,36 @@
+# 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 pytest
+import six
+
+from google.api_core.gapic_v2.dispatch import dispatch
+
+
+@pytest.mark.skipif(six.PY2, reason='dispatch only works on Python 3.')
+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/tests/unit/test_operation.py b/tests/unit/test_operation.py
index 211fea6..240eb86 100644
--- a/tests/unit/test_operation.py
+++ b/tests/unit/test_operation.py
@@ -221,3 +221,11 @@
     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)