Skip to content

Commit a2bebb9

Browse files
feat: adds new input validation function similar to isinstance. (#2107)
* feat: adds new function similar to isinstance. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent b35d741 commit a2bebb9

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

google/cloud/bigquery/_helpers.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import re
2323
import os
2424
import warnings
25-
from typing import Optional, Union
25+
from typing import Optional, Union, Any, Tuple, Type
2626

2727
from dateutil import relativedelta
2828
from google.cloud._helpers import UTC # type: ignore
@@ -1004,3 +1004,33 @@ def _verify_job_config_type(job_config, expected_type, param_name="job_config"):
10041004
job_config=job_config,
10051005
)
10061006
)
1007+
1008+
1009+
def _isinstance_or_raise(
1010+
value: Any,
1011+
dtype: Union[Type, Tuple[Type, ...]],
1012+
none_allowed: Optional[bool] = False,
1013+
) -> Any:
1014+
"""Determine whether a value type matches a given datatype or None.
1015+
Args:
1016+
value (Any): Value to be checked.
1017+
dtype (type): Expected data type or tuple of data types.
1018+
none_allowed Optional(bool): whether value is allowed to be None. Default
1019+
is False.
1020+
Returns:
1021+
Any: Returns the input value if the type check is successful.
1022+
Raises:
1023+
TypeError: If the input value's type does not match the expected data type(s).
1024+
"""
1025+
if none_allowed and value is None:
1026+
return value
1027+
1028+
if isinstance(value, dtype):
1029+
return value
1030+
1031+
or_none = ""
1032+
if none_allowed:
1033+
or_none = " (or None)"
1034+
1035+
msg = f"Pass {value} as a '{dtype}'{or_none}. Got {type(value)}."
1036+
raise TypeError(msg)

tests/unit/test__helpers.py

+32
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from unittest import mock
2525

2626
import google.api_core
27+
from google.cloud.bigquery._helpers import _isinstance_or_raise
2728

2829

2930
@pytest.mark.skipif(
@@ -1661,3 +1662,34 @@ def test_w_env_var(self):
16611662
host = self._call_fut()
16621663

16631664
self.assertEqual(host, HOST)
1665+
1666+
1667+
class Test__isinstance_or_raise:
1668+
@pytest.mark.parametrize(
1669+
"value,dtype,none_allowed,expected",
1670+
[
1671+
(None, str, True, None),
1672+
("hello world.uri", str, True, "hello world.uri"),
1673+
("hello world.uri", str, False, "hello world.uri"),
1674+
(None, (str, float), True, None),
1675+
("hello world.uri", (str, float), True, "hello world.uri"),
1676+
("hello world.uri", (str, float), False, "hello world.uri"),
1677+
],
1678+
)
1679+
def test__valid_isinstance_or_raise(self, value, dtype, none_allowed, expected):
1680+
result = _isinstance_or_raise(value, dtype, none_allowed=none_allowed)
1681+
assert result == expected
1682+
1683+
@pytest.mark.parametrize(
1684+
"value,dtype,none_allowed,expected",
1685+
[
1686+
(None, str, False, pytest.raises(TypeError)),
1687+
({"key": "value"}, str, True, pytest.raises(TypeError)),
1688+
({"key": "value"}, str, False, pytest.raises(TypeError)),
1689+
({"key": "value"}, (str, float), True, pytest.raises(TypeError)),
1690+
({"key": "value"}, (str, float), False, pytest.raises(TypeError)),
1691+
],
1692+
)
1693+
def test__invalid_isinstance_or_raise(self, value, dtype, none_allowed, expected):
1694+
with expected:
1695+
_isinstance_or_raise(value, dtype, none_allowed=none_allowed)

0 commit comments

Comments
 (0)