From 2eb64223983de916fc38e9fc9977b2476189301c Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 27 Sep 2019 10:13:51 +0200 Subject: [PATCH] fix(python): clear error message when trying to serialize function (#824) A common error seems to be to try to pass a function as a parameter into a JSII call (have seen 3 occurrences of this in the last week). Previously, this call would fail when trying to assing the `__jsii_type__` property to the function object. Specifically catch this case to give a helpful error message. Fixes aws/aws-cdk#4064. --- packages/jsii-python-runtime/src/jsii/_kernel/__init__.py | 6 ++++++ packages/jsii-python-runtime/tests/test_python.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py b/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py index 7fd163cbd2..1e7b2d47a7 100644 --- a/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py +++ b/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py @@ -1,6 +1,7 @@ import datetime import inspect import itertools +from types import FunctionType, MethodType, BuiltinFunctionType, LambdaType from typing import Any, List, Optional, Type, Union @@ -126,6 +127,11 @@ def _make_reference_for_native(kernel, d): return d elif isinstance(d, (int, type(None), str, float, bool, datetime.datetime)): return d + elif isinstance(d, (FunctionType, MethodType, BuiltinFunctionType, LambdaType)): + # Whether a given object is a function-like object. + # We won't use iscallable() since objects may implement __call__() + # but we still want to serialize them as normal. + raise JSIIError("Cannot pass function as argument here (did you mean to call this function?): %r" % d) else: d.__jsii__type__ = "Object" kernel.create(Object, d) diff --git a/packages/jsii-python-runtime/tests/test_python.py b/packages/jsii-python-runtime/tests/test_python.py index f81e9143e0..d4778f6774 100644 --- a/packages/jsii-python-runtime/tests/test_python.py +++ b/packages/jsii-python-runtime/tests/test_python.py @@ -23,6 +23,11 @@ def test_inheritance_maintained(self): assert base_names == ['DerivedStruct', 'MyFirstStruct'] + def test_descriptive_error_when_passing_function(self): + obj = jsii_calc.Calculator() + + with pytest.raises(JSIIError, match="Cannot pass function as argument here.*"): + obj.add(self.test_descriptive_error_when_passing_function) def find_struct_bases(x):