From d7f869cb3ca2ff57b1ac5ee56e8163d851fe0afe Mon Sep 17 00:00:00 2001 From: rafa-be Date: Fri, 28 Feb 2025 15:28:18 +0100 Subject: [PATCH] Improves the error message when and/or/not operators are used with Pargraph functions. --- pargraph/graph/decorators.py | 12 +++++++++++- tests/test_graph_generation.py | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pargraph/graph/decorators.py b/pargraph/graph/decorators.py index b65ef17..286708d 100644 --- a/pargraph/graph/decorators.py +++ b/pargraph/graph/decorators.py @@ -84,6 +84,14 @@ def call(*args) -> Any: return call(self, len(args), *args, *itertools.chain(*kwargs.items())) + def __bool__(self) -> bool: + # As Python does not allow the overloading of its and/or/not operators, we cannot implement + # our graph deduction mechanism on these. + # This implementation of __bool__ provides a more insightful error message when these + # operators are used on Pargraph functions. + # More info: https://peps.python.org/pep-0335/ + raise TypeError("Pargraph does not support the use of boolean (and/or/not) operators.") + def external_input() -> GraphContext: """ @@ -345,8 +353,10 @@ def _generate_graph(func: Callable, /, *args, **kwargs): # __hash__() is not included because since Python 3.3 hash randomization is enabled by default yielding impure hashes # between isolated instances making it not suitable for out-of-core computations # More info: https://docs.python.org/3/reference/datamodel.html#object.__hash__ +# +# __bool__() has a specific implementation, as Python does not support the overloading of its and/or operators (see +# GraphContext.__bool__ here-above). for op in { - bool, int, float, complex, diff --git a/tests/test_graph_generation.py b/tests/test_graph_generation.py index 604afb6..0de6ce2 100644 --- a/tests/test_graph_generation.py +++ b/tests/test_graph_generation.py @@ -149,6 +149,21 @@ def sample_graph(df1: pd.DataFrame, df2: pd.DataFrame) -> pd.DataFrame: ), ) + def test_boolean(self): + @delayed + def is_even(value: int) -> bool: + return value % 2 == 0 + + @delayed + def is_positive(value: int) -> bool: + return value >= 0 + + @graph + def invalid_graph(value: int) -> bool: + return is_even(value) or is_positive(value) + + self.assertRaises(TypeError, invalid_graph.to_graph) + def test_explode_subgraphs(self): @graph def sample_subgraph(x: int, y: int) -> int: