diff --git a/bigframes/functions/function_typing.py b/bigframes/functions/function_typing.py index 44ee071001..30804f317c 100644 --- a/bigframes/functions/function_typing.py +++ b/bigframes/functions/function_typing.py @@ -60,8 +60,22 @@ class UnsupportedTypeError(ValueError): def __init__(self, type_, supported_types): self.type = type_ self.supported_types = supported_types + + types_to_format = supported_types + if isinstance(supported_types, dict): + types_to_format = supported_types.keys() + + supported_types_str = ", ".join( + sorted( + [ + getattr(supported, "__name__", supported) + for supported in types_to_format + ] + ) + ) + super().__init__( - f"'{type_}' must be one of the supported types ({supported_types}) " + f"'{getattr(type_, '__name__', type_)}' must be one of the supported types ({supported_types_str}) " "or a list of one of those types." ) diff --git a/tests/system/small/functions/test_remote_function.py b/tests/system/small/functions/test_remote_function.py index 26c4b89b24..805505ecd5 100644 --- a/tests/system/small/functions/test_remote_function.py +++ b/tests/system/small/functions/test_remote_function.py @@ -1646,7 +1646,7 @@ def func_tuple(x): with pytest.raises( ValueError, - match=r"'typing\.Sequence\[int\]' must be one of the supported types", + match=r"must be one of the supported types", ): bff.remote_function( input_types=int, diff --git a/tests/unit/functions/test_function_typing.py b/tests/unit/functions/test_function_typing.py new file mode 100644 index 0000000000..46ae19555a --- /dev/null +++ b/tests/unit/functions/test_function_typing.py @@ -0,0 +1,50 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import decimal + +import pytest + +from bigframes.functions import function_typing + + +def test_unsupported_type_error_init_with_dict(): + err = function_typing.UnsupportedTypeError( + decimal.Decimal, {int: "INT64", float: "FLOAT64"} + ) + + message = str(err) + + assert "Decimal" in message + assert "float, int" in message + + +def test_unsupported_type_error_init_with_set(): + err = function_typing.UnsupportedTypeError(decimal.Decimal, {int, float}) + + message = str(err) + + assert "Decimal" in message + assert "float, int" in message + + +def test_sdk_type_from_python_type_raises_unsupported_type_error(): + with pytest.raises(function_typing.UnsupportedTypeError) as excinfo: + function_typing.sdk_type_from_python_type(datetime.datetime) + + message = str(excinfo.value) + + assert "datetime" in message + assert "bool, bytes, float, int, str" in message