Skip to content

Commit 947059a

Browse files
committed
Properly encode image content. Fixes #2525.
1 parent 853dd1a commit 947059a

File tree

3 files changed

+71
-66
lines changed

3 files changed

+71
-66
lines changed

packages/google-cloud-vision/google/cloud/vision/image.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from base64 import b64encode
1919

2020
from google.cloud._helpers import _to_bytes
21+
from google.cloud._helpers import _bytes_to_unicode
2122
from google.cloud.vision.entity import EntityAnnotation
2223
from google.cloud.vision.face import Face
2324
from google.cloud.vision.feature import Feature
@@ -47,7 +48,7 @@ def __init__(self, client, content=None, source_uri=None):
4748
if source_uri:
4849
self._source = source_uri
4950
else:
50-
self._content = b64encode(_to_bytes(content))
51+
self._content = _bytes_to_unicode(b64encode(_to_bytes(content)))
5152

5253
def as_dict(self):
5354
"""Generate dictionary structure for request.

packages/google-cloud-vision/unit_tests/test_client.py

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
15+
import base64
1616
import unittest
1717

1818
from google.cloud._helpers import _to_bytes
19+
from google.cloud._helpers import _bytes_to_unicode
1920

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

22+
IMAGE_CONTENT = _to_bytes('/9j/4QNURXhpZgAASUkq')
23+
IMAGE_SOURCE = 'gs://some/image.jpg'
24+
PROJECT = 'PROJECT'
25+
B64_IMAGE_CONTENT = _bytes_to_unicode(base64.b64encode(IMAGE_CONTENT))
2326

24-
class TestClient(unittest.TestCase):
25-
import base64
26-
PROJECT = 'PROJECT'
27-
B64_IMAGE_CONTENT = base64.b64encode(_IMAGE_CONTENT)
2827

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

3636
def test_ctor(self):
3737
creds = _Credentials()
38-
client = self._makeOne(project=self.PROJECT, credentials=creds)
39-
self.assertEqual(client.project, self.PROJECT)
38+
client = self._makeOne(project=PROJECT, credentials=creds)
39+
self.assertEqual(client.project, PROJECT)
4040

4141
def test_face_annotation(self):
4242
from google.cloud.vision.feature import Feature, FeatureTypes
@@ -47,7 +47,7 @@ def test_face_annotation(self):
4747
"requests": [
4848
{
4949
"image": {
50-
"content": self.B64_IMAGE_CONTENT
50+
"content": B64_IMAGE_CONTENT
5151
},
5252
"features": [
5353
{
@@ -59,12 +59,12 @@ def test_face_annotation(self):
5959
]
6060
}
6161
credentials = _Credentials()
62-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
62+
client = self._makeOne(project=PROJECT, credentials=credentials)
6363
client.connection = _Connection(RETURNED)
6464

6565
features = [Feature(feature_type=FeatureTypes.FACE_DETECTION,
6666
max_results=3)]
67-
image = client.image(content=_IMAGE_CONTENT)
67+
image = client.image(content=IMAGE_CONTENT)
6868
response = client.annotate(image, features)
6969

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

7777
credentials = _Credentials()
78-
client = self._makeOne(project=self.PROJECT,
78+
client = self._makeOne(project=PROJECT,
7979
credentials=credentials)
80-
image = client.image(source_uri=_IMAGE_SOURCE)
80+
image = client.image(source_uri=IMAGE_SOURCE)
8181
self.assertIsInstance(image, Image)
8282

8383
def test_face_detection_from_source(self):
8484
from google.cloud.vision.face import Face
8585
from unit_tests._fixtures import FACE_DETECTION_RESPONSE
8686
RETURNED = FACE_DETECTION_RESPONSE
8787
credentials = _Credentials()
88-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
88+
client = self._makeOne(project=PROJECT, credentials=credentials)
8989
client.connection = _Connection(RETURNED)
9090

91-
image = client.image(source_uri=_IMAGE_SOURCE)
91+
image = client.image(source_uri=IMAGE_SOURCE)
9292
faces = image.detect_faces(limit=3)
9393
self.assertEqual(5, len(faces))
9494
self.assertIsInstance(faces[0], Face)
9595
image_request = client.connection._requested[0]['data']['requests'][0]
96-
self.assertEqual(_IMAGE_SOURCE,
96+
self.assertEqual(IMAGE_SOURCE,
9797
image_request['image']['source']['gcs_image_uri'])
9898
self.assertEqual(3, image_request['features'][0]['maxResults'])
9999

@@ -102,15 +102,16 @@ def test_face_detection_from_content(self):
102102
from unit_tests._fixtures import FACE_DETECTION_RESPONSE
103103
RETURNED = FACE_DETECTION_RESPONSE
104104
credentials = _Credentials()
105-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
105+
client = self._makeOne(project=PROJECT, credentials=credentials)
106106
client.connection = _Connection(RETURNED)
107107

108-
image = client.image(content=_IMAGE_CONTENT)
108+
image = client.image(content=IMAGE_CONTENT)
109109
faces = image.detect_faces(limit=5)
110110
self.assertEqual(5, len(faces))
111111
self.assertIsInstance(faces[0], Face)
112112
image_request = client.connection._requested[0]['data']['requests'][0]
113-
self.assertEqual(self.B64_IMAGE_CONTENT,
113+
114+
self.assertEqual(B64_IMAGE_CONTENT,
114115
image_request['image']['content'])
115116
self.assertEqual(5, image_request['features'][0]['maxResults'])
116117

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

122123
credentials = _Credentials()
123-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
124+
client = self._makeOne(project=PROJECT, credentials=credentials)
124125
client.connection = _Connection(RETURNED)
125126

126-
image = client.image(source_uri=_IMAGE_SOURCE)
127+
image = client.image(source_uri=IMAGE_SOURCE)
127128
labels = image.detect_labels(limit=3)
128129
self.assertEqual(3, len(labels))
129130
self.assertIsInstance(labels[0], EntityAnnotation)
130131
image_request = client.connection._requested[0]['data']['requests'][0]
131-
self.assertEqual(_IMAGE_SOURCE,
132+
self.assertEqual(IMAGE_SOURCE,
132133
image_request['image']['source']['gcs_image_uri'])
133134
self.assertEqual(3, image_request['features'][0]['maxResults'])
134135
self.assertEqual('automobile', labels[0].description)
@@ -142,15 +143,15 @@ def test_landmark_detection_from_source(self):
142143
LANDMARK_DETECTION_RESPONSE as RETURNED)
143144

144145
credentials = _Credentials()
145-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
146+
client = self._makeOne(project=PROJECT, credentials=credentials)
146147
client.connection = _Connection(RETURNED)
147148

148-
image = client.image(source_uri=_IMAGE_SOURCE)
149+
image = client.image(source_uri=IMAGE_SOURCE)
149150
landmarks = image.detect_landmarks(limit=3)
150151
self.assertEqual(2, len(landmarks))
151152
self.assertIsInstance(landmarks[0], EntityAnnotation)
152153
image_request = client.connection._requested[0]['data']['requests'][0]
153-
self.assertEqual(_IMAGE_SOURCE,
154+
self.assertEqual(IMAGE_SOURCE,
154155
image_request['image']['source']['gcs_image_uri'])
155156
self.assertEqual(3, image_request['features'][0]['maxResults'])
156157
self.assertEqual(48.861013, landmarks[0].locations[0].latitude)
@@ -164,15 +165,15 @@ def test_landmark_detection_from_content(self):
164165
LANDMARK_DETECTION_RESPONSE as RETURNED)
165166

166167
credentials = _Credentials()
167-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
168+
client = self._makeOne(project=PROJECT, credentials=credentials)
168169
client.connection = _Connection(RETURNED)
169170

170-
image = client.image(content=_IMAGE_CONTENT)
171+
image = client.image(content=IMAGE_CONTENT)
171172
landmarks = image.detect_landmarks(limit=5)
172173
self.assertEqual(2, len(landmarks))
173174
self.assertIsInstance(landmarks[0], EntityAnnotation)
174175
image_request = client.connection._requested[0]['data']['requests'][0]
175-
self.assertEqual(self.B64_IMAGE_CONTENT,
176+
self.assertEqual(B64_IMAGE_CONTENT,
176177
image_request['image']['content'])
177178
self.assertEqual(5, image_request['features'][0]['maxResults'])
178179

@@ -181,15 +182,15 @@ def test_logo_detection_from_source(self):
181182
from unit_tests._fixtures import LOGO_DETECTION_RESPONSE
182183
RETURNED = LOGO_DETECTION_RESPONSE
183184
credentials = _Credentials()
184-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
185+
client = self._makeOne(project=PROJECT, credentials=credentials)
185186
client.connection = _Connection(RETURNED)
186187

187-
image = client.image(source_uri=_IMAGE_SOURCE)
188+
image = client.image(source_uri=IMAGE_SOURCE)
188189
logos = image.detect_logos(limit=3)
189190
self.assertEqual(2, len(logos))
190191
self.assertIsInstance(logos[0], EntityAnnotation)
191192
image_request = client.connection._requested[0]['data']['requests'][0]
192-
self.assertEqual(_IMAGE_SOURCE,
193+
self.assertEqual(IMAGE_SOURCE,
193194
image_request['image']['source']['gcs_image_uri'])
194195
self.assertEqual(3, image_request['features'][0]['maxResults'])
195196

@@ -198,15 +199,15 @@ def test_logo_detection_from_content(self):
198199
from unit_tests._fixtures import LOGO_DETECTION_RESPONSE
199200
RETURNED = LOGO_DETECTION_RESPONSE
200201
credentials = _Credentials()
201-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
202+
client = self._makeOne(project=PROJECT, credentials=credentials)
202203
client.connection = _Connection(RETURNED)
203204

204-
image = client.image(content=_IMAGE_CONTENT)
205+
image = client.image(content=IMAGE_CONTENT)
205206
logos = image.detect_logos(limit=5)
206207
self.assertEqual(2, len(logos))
207208
self.assertIsInstance(logos[0], EntityAnnotation)
208209
image_request = client.connection._requested[0]['data']['requests'][0]
209-
self.assertEqual(self.B64_IMAGE_CONTENT,
210+
self.assertEqual(B64_IMAGE_CONTENT,
210211
image_request['image']['content'])
211212
self.assertEqual(5, image_request['features'][0]['maxResults'])
212213

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

218219
credentials = _Credentials()
219-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
220+
client = self._makeOne(project=PROJECT, credentials=credentials)
220221
client.connection = _Connection(RETURNED)
221222

222-
image = client.image(source_uri=_IMAGE_SOURCE)
223+
image = client.image(source_uri=IMAGE_SOURCE)
223224
text = image.detect_text(limit=3)
224225
self.assertEqual(3, len(text))
225226
self.assertIsInstance(text[0], EntityAnnotation)
226227
image_request = client.connection._requested[0]['data']['requests'][0]
227-
self.assertEqual(_IMAGE_SOURCE,
228+
self.assertEqual(IMAGE_SOURCE,
228229
image_request['image']['source']['gcs_image_uri'])
229230
self.assertEqual(3, image_request['features'][0]['maxResults'])
230231
self.assertEqual('en', text[0].locale)
@@ -238,14 +239,14 @@ def test_safe_search_detection_from_source(self):
238239

239240
RETURNED = SAFE_SEARCH_DETECTION_RESPONSE
240241
credentials = _Credentials()
241-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
242+
client = self._makeOne(project=PROJECT, credentials=credentials)
242243
client.connection = _Connection(RETURNED)
243244

244-
image = client.image(source_uri=_IMAGE_SOURCE)
245+
image = client.image(source_uri=IMAGE_SOURCE)
245246
safe_search = image.detect_safe_search()
246247
self.assertIsInstance(safe_search, SafeSearchAnnotation)
247248
image_request = client.connection._requested[0]['data']['requests'][0]
248-
self.assertEqual(_IMAGE_SOURCE,
249+
self.assertEqual(IMAGE_SOURCE,
249250
image_request['image']['source']['gcs_image_uri'])
250251
self.assertEqual('VERY_UNLIKELY', safe_search.adult)
251252
self.assertEqual('UNLIKELY', safe_search.spoof)
@@ -258,14 +259,14 @@ def test_image_properties_detection_from_source(self):
258259

259260
RETURNED = IMAGE_PROPERTIES_RESPONSE
260261
credentials = _Credentials()
261-
client = self._makeOne(project=self.PROJECT, credentials=credentials)
262+
client = self._makeOne(project=PROJECT, credentials=credentials)
262263
client.connection = _Connection(RETURNED)
263264

264-
image = client.image(source_uri=_IMAGE_SOURCE)
265+
image = client.image(source_uri=IMAGE_SOURCE)
265266
image_properties = image.detect_properties()
266267
self.assertIsInstance(image_properties, ImagePropertiesAnnotation)
267268
image_request = client.connection._requested[0]['data']['requests'][0]
268-
self.assertEqual(_IMAGE_SOURCE,
269+
self.assertEqual(IMAGE_SOURCE,
269270
image_request['image']['source']['gcs_image_uri'])
270271
self.assertEqual(0.42258179, image_properties.colors[0].score)
271272
self.assertEqual(0.025376344,
@@ -289,14 +290,14 @@ def test_make_vision_request(self):
289290

290291
feature = Feature(feature_type=FeatureTypes.FACE_DETECTION,
291292
max_results=3)
292-
vision_request = self._makeOne(_IMAGE_CONTENT, feature)
293-
self.assertEqual(_IMAGE_CONTENT, vision_request.image)
293+
vision_request = self._makeOne(IMAGE_CONTENT, feature)
294+
self.assertEqual(IMAGE_CONTENT, vision_request.image)
294295
self.assertEqual(FeatureTypes.FACE_DETECTION,
295296
vision_request.features[0].feature_type)
296297

297298
def test_make_vision_request_with_bad_feature(self):
298299
with self.assertRaises(TypeError):
299-
self._makeOne(_IMAGE_CONTENT, 'nonsensefeature')
300+
self._makeOne(IMAGE_CONTENT, 'nonsensefeature')
300301

301302

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

321322
def api_request(self, **kw):
323+
import json
324+
json.dumps(kw.get('data', '')) # Simulate JSON encoding.
322325
self._requested.append(kw)
323326
response, self._responses = self._responses[0], self._responses[1:]
324327
return response

packages/google-cloud-vision/unit_tests/test_image.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,19 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import unittest
1615
import base64
16+
import unittest
1717

1818
from google.cloud._helpers import _to_bytes
19+
from google.cloud._helpers import _bytes_to_unicode
1920

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

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

27+
class TestVisionImage(unittest.TestCase):
2728
def _getTargetClass(self):
2829
from google.cloud.vision.image import Image
2930
return Image
@@ -32,37 +33,37 @@ def _makeOne(self, *args, **kw):
3233
return self._getTargetClass()(*args, **kw)
3334

3435
def test_image_source_type_content(self):
35-
image = self._makeOne(self._CLIENT_MOCK, content=self._IMAGE_CONTENT)
36+
image = self._makeOne(CLIENT_MOCK, content=IMAGE_CONTENT)
3637

3738
_AS_DICT = {
38-
'content': self._B64_IMAGE_CONTENT
39+
'content': B64_IMAGE_CONTENT
3940
}
4041

41-
self.assertEqual(self._B64_IMAGE_CONTENT, image.content)
42+
self.assertEqual(B64_IMAGE_CONTENT, image.content)
4243
self.assertEqual(None, image.source)
4344
self.assertEqual(_AS_DICT, image.as_dict())
4445

4546
def test_image_source_type_google_cloud_storage(self):
46-
image = self._makeOne(self._CLIENT_MOCK, source_uri=self._IMAGE_SOURCE)
47+
image = self._makeOne(CLIENT_MOCK, source_uri=IMAGE_SOURCE)
4748

4849
_AS_DICT = {
4950
'source': {
50-
'gcs_image_uri': self._IMAGE_SOURCE
51+
'gcs_image_uri': IMAGE_SOURCE
5152
}
5253
}
5354

54-
self.assertEqual(self._IMAGE_SOURCE, image.source)
55+
self.assertEqual(IMAGE_SOURCE, image.source)
5556
self.assertEqual(None, image.content)
5657
self.assertEqual(_AS_DICT, image.as_dict())
5758

5859
def test_cannot_set_both_source_and_content(self):
59-
image = self._makeOne(self._CLIENT_MOCK, content=self._IMAGE_CONTENT)
60+
image = self._makeOne(CLIENT_MOCK, content=IMAGE_CONTENT)
6061

61-
self.assertEqual(self._B64_IMAGE_CONTENT, image.content)
62+
self.assertEqual(B64_IMAGE_CONTENT, image.content)
6263
with self.assertRaises(AttributeError):
63-
image.source = self._IMAGE_SOURCE
64+
image.source = IMAGE_SOURCE
6465

65-
image = self._makeOne(self._CLIENT_MOCK, source_uri=self._IMAGE_SOURCE)
66-
self.assertEqual(self._IMAGE_SOURCE, image.source)
66+
image = self._makeOne(CLIENT_MOCK, source_uri=IMAGE_SOURCE)
67+
self.assertEqual(IMAGE_SOURCE, image.source)
6768
with self.assertRaises(AttributeError):
68-
image.content = self._IMAGE_CONTENT
69+
image.content = IMAGE_CONTENT

0 commit comments

Comments
 (0)