Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jimfulton committed Apr 27, 2021
1 parent f4e34c0 commit 4396e70
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 8 deletions.
20 changes: 16 additions & 4 deletions google/cloud/bigquery/dbapi/types.py
Expand Up @@ -30,16 +30,28 @@
TimestampFromTicks = datetime.datetime.fromtimestamp


def Binary(string):
def Binary(data):
"""Contruct a DB-API binary value.
Args:
string (str): A string to encode as a binary value.
data (bytes-like): An object containing binary data and that
can be converted to bytes with the `bytes` builtin.
Returns:
bytes: The UTF-8 encoded bytes representing the string.
bytes: The binary data as a bytes object.
"""
return string.encode("utf-8")
if isinstance(data, int):
# This is not the conversion we're looking for, because it
# will simply create a bytes object of the given size.
raise TypeError("cannot convert `int` object to binary")

try:
return bytes(data)
except TypeError:
if isinstance(data, str):
return data.encode("utf-8")
else:
raise


def TimeFromTicks(ticks, tz=None):
Expand Down
32 changes: 28 additions & 4 deletions tests/unit/test_dbapi_types.py
Expand Up @@ -15,6 +15,8 @@
import datetime
import unittest

import pytest

import google.cloud._helpers
from google.cloud.bigquery.dbapi import types

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

def test_binary_constructor(self):
self.assertEqual(types.Binary(u"hello"), b"hello")
self.assertEqual(types.Binary(u"\u1f60"), u"\u1f60".encode("utf-8"))

def test_timefromticks(self):
somedatetime = datetime.datetime(
2017, 2, 18, 12, 47, 26, tzinfo=google.cloud._helpers.UTC
Expand All @@ -40,3 +38,29 @@ def test_timefromticks(self):
types.TimeFromTicks(ticks, google.cloud._helpers.UTC),
datetime.time(12, 47, 26, tzinfo=google.cloud._helpers.UTC),
)


class CustomBinary:
def __bytes__(self):
return b"Google"


@pytest.mark.parametrize(
"raw,expected",
[
(u"hello", b"hello"),
(u"\u1f60", u"\u1f60".encode("utf-8")),
(b"hello", b"hello"),
(bytearray(b"hello"), b"hello"),
(memoryview(b"hello"), b"hello"),
(CustomBinary(), b"Google"),
],
)
def test_binary_constructor(raw, expected):
assert types.Binary(raw) == expected


@pytest.mark.parametrize("bad", (42, 42.0, None))
def test_invalid_binary_constructor(bad):
with pytest.raises(TypeError):
types.Binary(bad)

0 comments on commit 4396e70

Please sign in to comment.