From 7cb9e292cc7e2de30bc7be6c6d0fe6f5141aed48 Mon Sep 17 00:00:00 2001 From: Thomas Schultz Date: Tue, 3 Jan 2017 12:10:59 -0500 Subject: [PATCH] Add gRPC conversion helper functions. --- vision/google/cloud/vision/_gax.py | 47 +++++++++++++++++++++- vision/setup.py | 1 + vision/unit_tests/test__gax.py | 63 ++++++++++++++++++++++++++++-- vision/unit_tests/test_client.py | 17 ++++++-- 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/vision/google/cloud/vision/_gax.py b/vision/google/cloud/vision/_gax.py index 1bdba21a47df..1820d8a95860 100644 --- a/vision/google/cloud/vision/_gax.py +++ b/vision/google/cloud/vision/_gax.py @@ -14,12 +14,55 @@ """GAX Client for interacting with the Google Cloud Vision API.""" +from google.cloud.gapic.vision.v1 import image_annotator_client +from google.cloud.grpc.vision.v1 import image_annotator_pb2 + +from google.cloud._helpers import _to_bytes + class _GAPICVisionAPI(object): """Vision API for interacting with the gRPC version of Vision. - :type client: :class:`~google.cloud.core.client.Client` + :type client: :class:`~google.cloud.vision.client.Client` :param client: Instance of ``Client`` object. """ def __init__(self, client=None): - raise NotImplementedError + self._client = client + self._api = image_annotator_client.ImageAnnotatorClient() + + +def _to_gapic_feature(feature): + """Helper function to convert a ``Feature`` to a gRPC ``Feature``. + + :type feature: :class:`~google.cloud.vision.feature.Feature` + :param feature: Local ``Feature`` class to be converted to gRPC ``Feature`` + instance. + + :rtype: :class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.Feature` + :returns: gRPC ``Feature`` converted from + :class:`~google.cloud.vision.feature.Feature`. + """ + return image_annotator_pb2.Feature( + type=getattr(image_annotator_pb2.Feature, feature.feature_type), + max_results=feature.max_results) + + +def _to_gapic_image(image): + """Helper function to convert an ``Image`` to a gRPC ``Image``. + + :type image: :class:`~google.cloud.vision.image.Image` + :param image: Local ``Image`` class to be converted to gRPC ``Image``. + + :rtype: :class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.Image` + :returns: gRPC ``Image`` converted from + :class:`~google.cloud.vision.image.Image`. + """ + if image.content is not None: + return image_annotator_pb2.Image(content=_to_bytes(image.content)) + if image.source is not None: + return image_annotator_pb2.Image( + source=image_annotator_pb2.ImageSource( + gcs_image_uri=image.source + ), + ) + raise ValueError('No image content or source found.') diff --git a/vision/setup.py b/vision/setup.py index 9d193b30c1b0..7915c92850ad 100644 --- a/vision/setup.py +++ b/vision/setup.py @@ -52,6 +52,7 @@ REQUIREMENTS = [ 'enum34', 'google-cloud-core >= 0.22.1, < 0.23dev', + 'gapic-google-cloud-vision-v1 >= 0.14.0, < 0.15dev', ] setup( diff --git a/vision/unit_tests/test__gax.py b/vision/unit_tests/test__gax.py index 108f9be3bfc3..887592844395 100644 --- a/vision/unit_tests/test__gax.py +++ b/vision/unit_tests/test__gax.py @@ -14,6 +14,8 @@ import unittest +import mock + class TestGAXClient(unittest.TestCase): def _get_target_class(self): @@ -23,7 +25,62 @@ def _get_target_class(self): def _make_one(self, *args, **kwargs): return self._get_target_class()(*args, **kwargs) - def test_gax_not_implemented(self): + def test_ctor(self): + client = mock.Mock() + with mock.patch('google.cloud.vision._gax.image_annotator_client.' + 'ImageAnnotatorClient'): + api = self._make_one(client) + self.assertIs(api._client, client) + + +class TestToGAPICFeature(unittest.TestCase): + def _call_fut(self, feature): + from google.cloud.vision._gax import _to_gapic_feature + return _to_gapic_feature(feature) + + def test__to_gapic_feature(self): + from google.cloud.vision.feature import Feature + from google.cloud.vision.feature import FeatureTypes + from google.cloud.grpc.vision.v1 import image_annotator_pb2 + + feature = Feature(FeatureTypes.LABEL_DETECTION, 5) + feature_pb = self._call_fut(feature) + self.assertIsInstance(feature_pb, image_annotator_pb2.Feature) + self.assertEqual(feature_pb.type, 4) + self.assertEqual(feature_pb.max_results, 5) + + +class TestToGAPICImage(unittest.TestCase): + def _call_fut(self, image): + from google.cloud.vision._gax import _to_gapic_image + return _to_gapic_image(image) + + def test__to_gapic_image_content(self): + import base64 + from google.cloud.vision.image import Image + from google.cloud.grpc.vision.v1 import image_annotator_pb2 + + image_content = b'abc 1 2 3' + b64_content = base64.b64encode(image_content) + client = object() + image = Image(client, content=image_content) + image_pb = self._call_fut(image) + self.assertIsInstance(image_pb, image_annotator_pb2.Image) + self.assertEqual(image_pb.content, b64_content) + + def test__to_gapic_image_uri(self): + from google.cloud.vision.image import Image + from google.cloud.grpc.vision.v1 import image_annotator_pb2 + + image_uri = 'gs://1234/34.jpg' client = object() - with self.assertRaises(NotImplementedError): - self._make_one(client=client) + image = Image(client, source_uri=image_uri) + image_pb = self._call_fut(image) + self.assertIsInstance(image_pb, image_annotator_pb2.Image) + self.assertEqual(image_pb.source.gcs_image_uri, image_uri) + + def test__to_gapic_with_empty_image(self): + image = mock.Mock( + content=None, source=None, spec=['content', 'source']) + with self.assertRaises(ValueError): + self._call_fut(image) diff --git a/vision/unit_tests/test_client.py b/vision/unit_tests/test_client.py index aadb8676d3e7..44f76e944012 100644 --- a/vision/unit_tests/test_client.py +++ b/vision/unit_tests/test_client.py @@ -55,14 +55,25 @@ def test_annotate_with_preset_api(self): client._vision_api.annotate() api.annotate.assert_called_once_with() - def test_gax_not_implemented_from_client(self): + def test_make_gax_client(self): + from google.cloud.vision._gax import _GAPICVisionAPI + credentials = _make_credentials() client = self._make_one(project=PROJECT, credentials=credentials, use_gax=None) client._connection = _Connection() + with mock.patch('google.cloud.vision.client._GAPICVisionAPI', + spec=True): + self.assertIsInstance(client._vision_api, _GAPICVisionAPI) + + def test_make_http_client(self): + from google.cloud.vision._http import _HTTPVisionAPI - with self.assertRaises(NotImplementedError): - client._vision_api() + credentials = _make_credentials() + client = self._make_one(project=PROJECT, credentials=credentials, + use_gax=False) + client._connection = _Connection() + self.assertIsInstance(client._vision_api, _HTTPVisionAPI) def test_face_annotation(self): from google.cloud.vision.feature import Feature, FeatureTypes