Skip to content

Commit

Permalink
Properly encode image content. Fixes #2525.
Browse files Browse the repository at this point in the history
  • Loading branch information
daspecster committed Oct 12, 2016
1 parent 853dd1a commit 947059a
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 66 deletions.
3 changes: 2 additions & 1 deletion packages/google-cloud-vision/google/cloud/vision/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from base64 import b64encode

from google.cloud._helpers import _to_bytes
from google.cloud._helpers import _bytes_to_unicode
from google.cloud.vision.entity import EntityAnnotation
from google.cloud.vision.face import Face
from google.cloud.vision.feature import Feature
Expand Down Expand Up @@ -47,7 +48,7 @@ def __init__(self, client, content=None, source_uri=None):
if source_uri:
self._source = source_uri
else:
self._content = b64encode(_to_bytes(content))
self._content = _bytes_to_unicode(b64encode(_to_bytes(content)))

def as_dict(self):
"""Generate dictionary structure for request.
Expand Down
97 changes: 50 additions & 47 deletions packages/google-cloud-vision/unit_tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.


import base64
import unittest

from google.cloud._helpers import _to_bytes
from google.cloud._helpers import _bytes_to_unicode

_IMAGE_CONTENT = _to_bytes('/9j/4QNURXhpZgAASUkq')
_IMAGE_SOURCE = 'gs://some/image.jpg'

IMAGE_CONTENT = _to_bytes('/9j/4QNURXhpZgAASUkq')
IMAGE_SOURCE = 'gs://some/image.jpg'
PROJECT = 'PROJECT'
B64_IMAGE_CONTENT = _bytes_to_unicode(base64.b64encode(IMAGE_CONTENT))

class TestClient(unittest.TestCase):
import base64
PROJECT = 'PROJECT'
B64_IMAGE_CONTENT = base64.b64encode(_IMAGE_CONTENT)

class TestClient(unittest.TestCase):
def _getTargetClass(self):
from google.cloud.vision.client import Client
return Client
Expand All @@ -35,8 +35,8 @@ def _makeOne(self, *args, **kw):

def test_ctor(self):
creds = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=creds)
self.assertEqual(client.project, self.PROJECT)
client = self._makeOne(project=PROJECT, credentials=creds)
self.assertEqual(client.project, PROJECT)

def test_face_annotation(self):
from google.cloud.vision.feature import Feature, FeatureTypes
Expand All @@ -47,7 +47,7 @@ def test_face_annotation(self):
"requests": [
{
"image": {
"content": self.B64_IMAGE_CONTENT
"content": B64_IMAGE_CONTENT
},
"features": [
{
Expand All @@ -59,12 +59,12 @@ def test_face_annotation(self):
]
}
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

features = [Feature(feature_type=FeatureTypes.FACE_DETECTION,
max_results=3)]
image = client.image(content=_IMAGE_CONTENT)
image = client.image(content=IMAGE_CONTENT)
response = client.annotate(image, features)

self.assertEqual(REQUEST,
Expand All @@ -75,25 +75,25 @@ def test_image_with_client(self):
from google.cloud.vision.image import Image

credentials = _Credentials()
client = self._makeOne(project=self.PROJECT,
client = self._makeOne(project=PROJECT,
credentials=credentials)
image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
self.assertIsInstance(image, Image)

def test_face_detection_from_source(self):
from google.cloud.vision.face import Face
from unit_tests._fixtures import FACE_DETECTION_RESPONSE
RETURNED = FACE_DETECTION_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
faces = image.detect_faces(limit=3)
self.assertEqual(5, len(faces))
self.assertIsInstance(faces[0], Face)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(3, image_request['features'][0]['maxResults'])

Expand All @@ -102,15 +102,16 @@ def test_face_detection_from_content(self):
from unit_tests._fixtures import FACE_DETECTION_RESPONSE
RETURNED = FACE_DETECTION_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(content=_IMAGE_CONTENT)
image = client.image(content=IMAGE_CONTENT)
faces = image.detect_faces(limit=5)
self.assertEqual(5, len(faces))
self.assertIsInstance(faces[0], Face)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(self.B64_IMAGE_CONTENT,

self.assertEqual(B64_IMAGE_CONTENT,
image_request['image']['content'])
self.assertEqual(5, image_request['features'][0]['maxResults'])

Expand All @@ -120,15 +121,15 @@ def test_label_detection_from_source(self):
LABEL_DETECTION_RESPONSE as RETURNED)

credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
labels = image.detect_labels(limit=3)
self.assertEqual(3, len(labels))
self.assertIsInstance(labels[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(3, image_request['features'][0]['maxResults'])
self.assertEqual('automobile', labels[0].description)
Expand All @@ -142,15 +143,15 @@ def test_landmark_detection_from_source(self):
LANDMARK_DETECTION_RESPONSE as RETURNED)

credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
landmarks = image.detect_landmarks(limit=3)
self.assertEqual(2, len(landmarks))
self.assertIsInstance(landmarks[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(3, image_request['features'][0]['maxResults'])
self.assertEqual(48.861013, landmarks[0].locations[0].latitude)
Expand All @@ -164,15 +165,15 @@ def test_landmark_detection_from_content(self):
LANDMARK_DETECTION_RESPONSE as RETURNED)

credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(content=_IMAGE_CONTENT)
image = client.image(content=IMAGE_CONTENT)
landmarks = image.detect_landmarks(limit=5)
self.assertEqual(2, len(landmarks))
self.assertIsInstance(landmarks[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(self.B64_IMAGE_CONTENT,
self.assertEqual(B64_IMAGE_CONTENT,
image_request['image']['content'])
self.assertEqual(5, image_request['features'][0]['maxResults'])

Expand All @@ -181,15 +182,15 @@ def test_logo_detection_from_source(self):
from unit_tests._fixtures import LOGO_DETECTION_RESPONSE
RETURNED = LOGO_DETECTION_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
logos = image.detect_logos(limit=3)
self.assertEqual(2, len(logos))
self.assertIsInstance(logos[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(3, image_request['features'][0]['maxResults'])

Expand All @@ -198,15 +199,15 @@ def test_logo_detection_from_content(self):
from unit_tests._fixtures import LOGO_DETECTION_RESPONSE
RETURNED = LOGO_DETECTION_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(content=_IMAGE_CONTENT)
image = client.image(content=IMAGE_CONTENT)
logos = image.detect_logos(limit=5)
self.assertEqual(2, len(logos))
self.assertIsInstance(logos[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(self.B64_IMAGE_CONTENT,
self.assertEqual(B64_IMAGE_CONTENT,
image_request['image']['content'])
self.assertEqual(5, image_request['features'][0]['maxResults'])

Expand All @@ -216,15 +217,15 @@ def test_text_detection_from_source(self):
TEXT_DETECTION_RESPONSE as RETURNED)

credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
text = image.detect_text(limit=3)
self.assertEqual(3, len(text))
self.assertIsInstance(text[0], EntityAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(3, image_request['features'][0]['maxResults'])
self.assertEqual('en', text[0].locale)
Expand All @@ -238,14 +239,14 @@ def test_safe_search_detection_from_source(self):

RETURNED = SAFE_SEARCH_DETECTION_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
safe_search = image.detect_safe_search()
self.assertIsInstance(safe_search, SafeSearchAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual('VERY_UNLIKELY', safe_search.adult)
self.assertEqual('UNLIKELY', safe_search.spoof)
Expand All @@ -258,14 +259,14 @@ def test_image_properties_detection_from_source(self):

RETURNED = IMAGE_PROPERTIES_RESPONSE
credentials = _Credentials()
client = self._makeOne(project=self.PROJECT, credentials=credentials)
client = self._makeOne(project=PROJECT, credentials=credentials)
client.connection = _Connection(RETURNED)

image = client.image(source_uri=_IMAGE_SOURCE)
image = client.image(source_uri=IMAGE_SOURCE)
image_properties = image.detect_properties()
self.assertIsInstance(image_properties, ImagePropertiesAnnotation)
image_request = client.connection._requested[0]['data']['requests'][0]
self.assertEqual(_IMAGE_SOURCE,
self.assertEqual(IMAGE_SOURCE,
image_request['image']['source']['gcs_image_uri'])
self.assertEqual(0.42258179, image_properties.colors[0].score)
self.assertEqual(0.025376344,
Expand All @@ -289,14 +290,14 @@ def test_make_vision_request(self):

feature = Feature(feature_type=FeatureTypes.FACE_DETECTION,
max_results=3)
vision_request = self._makeOne(_IMAGE_CONTENT, feature)
self.assertEqual(_IMAGE_CONTENT, vision_request.image)
vision_request = self._makeOne(IMAGE_CONTENT, feature)
self.assertEqual(IMAGE_CONTENT, vision_request.image)
self.assertEqual(FeatureTypes.FACE_DETECTION,
vision_request.features[0].feature_type)

def test_make_vision_request_with_bad_feature(self):
with self.assertRaises(TypeError):
self._makeOne(_IMAGE_CONTENT, 'nonsensefeature')
self._makeOne(IMAGE_CONTENT, 'nonsensefeature')


class _Credentials(object):
Expand All @@ -319,6 +320,8 @@ def __init__(self, *responses):
self._requested = []

def api_request(self, **kw):
import json
json.dumps(kw.get('data', '')) # Simulate JSON encoding.
self._requested.append(kw)
response, self._responses = self._responses[0], self._responses[1:]
return response
37 changes: 19 additions & 18 deletions packages/google-cloud-vision/unit_tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest
import base64
import unittest

from google.cloud._helpers import _to_bytes
from google.cloud._helpers import _bytes_to_unicode

IMAGE_SOURCE = 'gs://some/image.jpg'
IMAGE_CONTENT = _to_bytes('/9j/4QNURXhpZgAASUkq')
B64_IMAGE_CONTENT = _bytes_to_unicode(base64.b64encode(IMAGE_CONTENT))
CLIENT_MOCK = {'source': ''}

class TestVisionImage(unittest.TestCase):
_IMAGE_SOURCE = 'gs://some/image.jpg'
_IMAGE_CONTENT = _to_bytes('/9j/4QNURXhpZgAASUkq')
_B64_IMAGE_CONTENT = base64.b64encode(_IMAGE_CONTENT)
_CLIENT_MOCK = {'source': ''}

class TestVisionImage(unittest.TestCase):
def _getTargetClass(self):
from google.cloud.vision.image import Image
return Image
Expand All @@ -32,37 +33,37 @@ def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_image_source_type_content(self):
image = self._makeOne(self._CLIENT_MOCK, content=self._IMAGE_CONTENT)
image = self._makeOne(CLIENT_MOCK, content=IMAGE_CONTENT)

_AS_DICT = {
'content': self._B64_IMAGE_CONTENT
'content': B64_IMAGE_CONTENT
}

self.assertEqual(self._B64_IMAGE_CONTENT, image.content)
self.assertEqual(B64_IMAGE_CONTENT, image.content)
self.assertEqual(None, image.source)
self.assertEqual(_AS_DICT, image.as_dict())

def test_image_source_type_google_cloud_storage(self):
image = self._makeOne(self._CLIENT_MOCK, source_uri=self._IMAGE_SOURCE)
image = self._makeOne(CLIENT_MOCK, source_uri=IMAGE_SOURCE)

_AS_DICT = {
'source': {
'gcs_image_uri': self._IMAGE_SOURCE
'gcs_image_uri': IMAGE_SOURCE
}
}

self.assertEqual(self._IMAGE_SOURCE, image.source)
self.assertEqual(IMAGE_SOURCE, image.source)
self.assertEqual(None, image.content)
self.assertEqual(_AS_DICT, image.as_dict())

def test_cannot_set_both_source_and_content(self):
image = self._makeOne(self._CLIENT_MOCK, content=self._IMAGE_CONTENT)
image = self._makeOne(CLIENT_MOCK, content=IMAGE_CONTENT)

self.assertEqual(self._B64_IMAGE_CONTENT, image.content)
self.assertEqual(B64_IMAGE_CONTENT, image.content)
with self.assertRaises(AttributeError):
image.source = self._IMAGE_SOURCE
image.source = IMAGE_SOURCE

image = self._makeOne(self._CLIENT_MOCK, source_uri=self._IMAGE_SOURCE)
self.assertEqual(self._IMAGE_SOURCE, image.source)
image = self._makeOne(CLIENT_MOCK, source_uri=IMAGE_SOURCE)
self.assertEqual(IMAGE_SOURCE, image.source)
with self.assertRaises(AttributeError):
image.content = self._IMAGE_CONTENT
image.content = IMAGE_CONTENT

0 comments on commit 947059a

Please sign in to comment.