Skip to content

Commit 4396e70

Browse files
author
Jim Fulton
authored
fix: The DB API Binary function accepts bytes data (#630)
* fix: The DB API Binary function accepts bytes data * Binary should accept bytes-like objects. * check for an integer before converting to bytes. Because we don't want to accidentally create a giant bytes. * blackened. * Fixed exception string. * parameterized binary tests and rearranged imports. * typo * Blackened
1 parent f4e34c0 commit 4396e70

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

google/cloud/bigquery/dbapi/types.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,28 @@
3030
TimestampFromTicks = datetime.datetime.fromtimestamp
3131

3232

33-
def Binary(string):
33+
def Binary(data):
3434
"""Contruct a DB-API binary value.
3535
3636
Args:
37-
string (str): A string to encode as a binary value.
37+
data (bytes-like): An object containing binary data and that
38+
can be converted to bytes with the `bytes` builtin.
3839
3940
Returns:
40-
bytes: The UTF-8 encoded bytes representing the string.
41+
bytes: The binary data as a bytes object.
4142
"""
42-
return string.encode("utf-8")
43+
if isinstance(data, int):
44+
# This is not the conversion we're looking for, because it
45+
# will simply create a bytes object of the given size.
46+
raise TypeError("cannot convert `int` object to binary")
47+
48+
try:
49+
return bytes(data)
50+
except TypeError:
51+
if isinstance(data, str):
52+
return data.encode("utf-8")
53+
else:
54+
raise
4355

4456

4557
def TimeFromTicks(ticks, tz=None):

tests/unit/test_dbapi_types.py

+28-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import datetime
1616
import unittest
1717

18+
import pytest
19+
1820
import google.cloud._helpers
1921
from google.cloud.bigquery.dbapi import types
2022

@@ -26,10 +28,6 @@ def test_binary_type(self):
2628
self.assertEqual("STRUCT", types.BINARY)
2729
self.assertNotEqual("STRING", types.BINARY)
2830

29-
def test_binary_constructor(self):
30-
self.assertEqual(types.Binary(u"hello"), b"hello")
31-
self.assertEqual(types.Binary(u"\u1f60"), u"\u1f60".encode("utf-8"))
32-
3331
def test_timefromticks(self):
3432
somedatetime = datetime.datetime(
3533
2017, 2, 18, 12, 47, 26, tzinfo=google.cloud._helpers.UTC
@@ -40,3 +38,29 @@ def test_timefromticks(self):
4038
types.TimeFromTicks(ticks, google.cloud._helpers.UTC),
4139
datetime.time(12, 47, 26, tzinfo=google.cloud._helpers.UTC),
4240
)
41+
42+
43+
class CustomBinary:
44+
def __bytes__(self):
45+
return b"Google"
46+
47+
48+
@pytest.mark.parametrize(
49+
"raw,expected",
50+
[
51+
(u"hello", b"hello"),
52+
(u"\u1f60", u"\u1f60".encode("utf-8")),
53+
(b"hello", b"hello"),
54+
(bytearray(b"hello"), b"hello"),
55+
(memoryview(b"hello"), b"hello"),
56+
(CustomBinary(), b"Google"),
57+
],
58+
)
59+
def test_binary_constructor(raw, expected):
60+
assert types.Binary(raw) == expected
61+
62+
63+
@pytest.mark.parametrize("bad", (42, 42.0, None))
64+
def test_invalid_binary_constructor(bad):
65+
with pytest.raises(TypeError):
66+
types.Binary(bad)

0 commit comments

Comments
 (0)