diff --git a/CHANGES.current b/CHANGES.current index 529680e7c..9b0642ef4 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,62 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.0 (in progress) ============================ +2014-03-06: wsfulton + [Python] Change in default behaviour wrapping C++ bool. Only a Python True or False + will now work for C++ bool parameters. This fixes overloading bool with other types. + Python 2.3 minimum is now required for wrapping bool. + + When wrapping: + + const char* overloaded(bool value) { return "bool"; } + const char* overloaded(int value) { return "int"; } + + Previous behaviour: + >>> overloaded(False) + 'int' + >>> overloaded(True) + 'int' + >>> overloaded(0) + 'int' + + Now we get the expected behaviour: + >>> overloaded(False) + 'bool' + >>> overloaded(0) + 'int' + + The consequence is when wrapping bool in non-overloaded functions: + + const char* boolfunction(bool value) { return value ? "true" : "false"; } + + The previous behaviour was very Pythonic: + >>> boolfunction("") + 'false' + >>> boolfunction("hi") + 'true' + >>> boolfunction(12.34) + 'true' + >>> boolfunction(0) + 'false' + >>> boolfunction(1) + 'true' + + Now the new behaviour more along the lines of C++ due to stricter type checking. The + above calls result in an exception and need to be explicitly converted into a bool as + follows: + >>> boolfunction(0) + Traceback (most recent call last): + File "", line 1, in + TypeError: in method 'boolfunction', argument 1 of type 'bool' + >>> boolfunction(bool(0)) + 'false' + + The old behaviour can be resurrected by passing the -DSWIG_PYTHON_LEGACY_BOOL command line + parameter when executing SWIG. Typemaps can of course be written to customise the behaviour + for specific parameters. + + *** POTENTIAL INCOMPATIBILITY *** + 2014-03-06: wsfulton Fix SF Bug #1363 - Problem with method overloading when some methods are added by %extend and others are real methods and using template default parameters with smart pointers. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 1d8a4f04f..4466558fb 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -294,6 +294,7 @@ CPP_TEST_CASES += \ operator_pointer_ref \ operbool \ ordering \ + overload_bool \ overload_copy \ overload_extend \ overload_method \ diff --git a/Examples/test-suite/overload_bool.i b/Examples/test-suite/overload_bool.i new file mode 100644 index 000000000..d48bfc299 --- /dev/null +++ b/Examples/test-suite/overload_bool.i @@ -0,0 +1,19 @@ +%module overload_bool + +%inline %{ +const char* overloaded(bool value) { return "bool"; } +const char* overloaded(int value) { return "int"; } +const char* overloaded(const char *value) { return "string"; } + +const char* boolfunction(bool value) { return value ? "true" : "false"; } +const char* intfunction(int value) { return "int"; } + + +// Const references +const char* overloaded_ref(bool const& value) { return "bool"; } +const char* overloaded_ref(int const& value) { return "int"; } +const char* overloaded_ref(const char *value) { return "string"; } + +const char* boolfunction_ref(bool const& value) { return value ? "true" : "false"; } +const char* intfunction_ref(int const& value) { return "int"; } +%} diff --git a/Examples/test-suite/python/li_std_vector_extra_runme.py b/Examples/test-suite/python/li_std_vector_extra_runme.py index 8900d7298..d24d36cb6 100644 --- a/Examples/test-suite/python/li_std_vector_extra_runme.py +++ b/Examples/test-suite/python/li_std_vector_extra_runme.py @@ -17,10 +17,10 @@ halve_in_place(dv) bv = BoolVector(4) -bv[0]= 1 -bv[1]= 0 -bv[2]= 4 -bv[3]= 0 +bv[0]= bool(1) +bv[1]= bool(0) +bv[2]= bool(4) +bv[3]= bool(0) if bv[0] != bv[2]: raise RuntimeError,"bad std::vector mapping" diff --git a/Examples/test-suite/python/overload_bool_runme.py b/Examples/test-suite/python/overload_bool_runme.py new file mode 100644 index 000000000..ed7d1b5a1 --- /dev/null +++ b/Examples/test-suite/python/overload_bool_runme.py @@ -0,0 +1,55 @@ +import overload_bool + +# Overloading bool, int, string +if overload_bool.overloaded(True) != "bool": + raise RuntimeError("wrong!") +if overload_bool.overloaded(False) != "bool": + raise RuntimeError("wrong!") + +if overload_bool.overloaded(0) != "int": + raise RuntimeError("wrong!") +if overload_bool.overloaded(1) != "int": + raise RuntimeError("wrong!") +if overload_bool.overloaded(2) != "int": + raise RuntimeError("wrong!") + +if overload_bool.overloaded("1234") != "string": + raise RuntimeError("wrong!") + +# Test bool masquerading as int +if overload_bool.intfunction(True) != "int": + raise RuntimeError("wrong!") +if overload_bool.intfunction(False) != "int": + raise RuntimeError("wrong!") + +# Test int masquerading as bool +# Not possible + + +############################################# + +# Overloading bool, int, string +if overload_bool.overloaded_ref(True) != "bool": + raise RuntimeError("wrong!") +if overload_bool.overloaded_ref(False) != "bool": + raise RuntimeError("wrong!") + +if overload_bool.overloaded_ref(0) != "int": + raise RuntimeError("wrong!") +if overload_bool.overloaded_ref(1) != "int": + raise RuntimeError("wrong!") +if overload_bool.overloaded_ref(2) != "int": + raise RuntimeError("wrong!") + +if overload_bool.overloaded_ref("1234") != "string": + raise RuntimeError("wrong!") + +# Test bool masquerading as int +if overload_bool.intfunction_ref(True) != "int": + raise RuntimeError("wrong!") +if overload_bool.intfunction_ref(False) != "int": + raise RuntimeError("wrong!") + +# Test int masquerading as bool +# Not possible + diff --git a/Examples/test-suite/python/primitive_ref_runme.py b/Examples/test-suite/python/primitive_ref_runme.py index 7ce872a62..f3a640389 100644 --- a/Examples/test-suite/python/primitive_ref_runme.py +++ b/Examples/test-suite/python/primitive_ref_runme.py @@ -30,7 +30,7 @@ if ref_float(3.5) != 3.5: if ref_double(3.5) != 3.5: raise RuntimeError -if ref_bool(1) != 1: +if ref_bool(True) != True: raise RuntimeError if ref_char('x') != 'x': diff --git a/Examples/test-suite/python/reference_global_vars_runme.py b/Examples/test-suite/python/reference_global_vars_runme.py index aa42ff50b..98aaec5fe 100644 --- a/Examples/test-suite/python/reference_global_vars_runme.py +++ b/Examples/test-suite/python/reference_global_vars_runme.py @@ -5,12 +5,12 @@ if getconstTC().num != 33: raise RuntimeError # primitive reference variables -cvar.var_bool = createref_bool(0) -if value_bool(cvar.var_bool) != 0: +cvar.var_bool = createref_bool(False) +if value_bool(cvar.var_bool) != False: raise RuntimeError -cvar.var_bool = createref_bool(1) -if value_bool(cvar.var_bool) != 1: +cvar.var_bool = createref_bool(True) +if value_bool(cvar.var_bool) != True: raise RuntimeError cvar.var_char = createref_char('w') diff --git a/Examples/test-suite/python/std_containers_runme.py b/Examples/test-suite/python/std_containers_runme.py index bed59bb29..f90c98405 100644 --- a/Examples/test-suite/python/std_containers_runme.py +++ b/Examples/test-suite/python/std_containers_runme.py @@ -46,7 +46,7 @@ for i in range(0,len(m)): if m[i][j] != im[i][j]: raise RuntimeError, "bad getslice" -m = ((1,0,1),(1,1),(1,1)) +m = ((True,False,True),(True,True),(True,True)) im = std_containers.midentb(m) for i in range(0,len(m)): for j in range(0,len(m[i])): diff --git a/Examples/test-suite/ruby/overload_bool_runme.rb b/Examples/test-suite/ruby/overload_bool_runme.rb new file mode 100755 index 000000000..8b7568e94 --- /dev/null +++ b/Examples/test-suite/ruby/overload_bool_runme.rb @@ -0,0 +1,88 @@ +#!/usr/bin/env ruby +# +# Put description here +# +# +# +# +# + +require 'swig_assert' + +require 'overload_bool' + +include Overload_bool + +# Overloading bool, int, string +if overloaded(true) != "bool" + raise RuntimeError, "wrong!" +end +if overloaded(false) != "bool" + raise RuntimeError, "wrong!" +end + +if overloaded(0) != "int" + raise RuntimeError, "wrong!" +end +if overloaded(1) != "int" + raise RuntimeError, "wrong!" +end +if overloaded(2) != "int" + raise RuntimeError, "wrong!" +end + +if overloaded("1234") != "string" + raise RuntimeError, "wrong!" +end + +# Test bool masquerading as integer +# Not possible + +# Test int masquerading as bool +if boolfunction(0) != "false" + raise RuntimeError, "wrong!" +end +if boolfunction(1) != "true" + raise RuntimeError, "wrong!" +end +if boolfunction(2) != "true" + raise RuntimeError, "wrong!" +end + +############################################# + +# Overloading bool, int, string +if overloaded_ref(true) != "bool" + raise RuntimeError, "wrong!" +end +if overloaded_ref(false) != "bool" + raise RuntimeError, "wrong!" +end + +if overloaded_ref(0) != "int" + raise RuntimeError, "wrong!" +end +if overloaded_ref(1) != "int" + raise RuntimeError, "wrong!" +end +if overloaded_ref(2) != "int" + raise RuntimeError, "wrong!" +end + +if overloaded_ref("1234") != "string" + raise RuntimeError, "wrong!" +end + +# Test bool masquerading as integer +# Not possible + +# Test int masquerading as bool +if boolfunction_ref(0) != "false" + raise RuntimeError, "wrong!" +end +if boolfunction_ref(1) != "true" + raise RuntimeError, "wrong!" +end +if boolfunction_ref(2) != "true" + raise RuntimeError, "wrong!" +end diff --git a/Lib/python/pyprimtypes.swg b/Lib/python/pyprimtypes.swg index 66ff104a6..30bb64f66 100644 --- a/Lib/python/pyprimtypes.swg +++ b/Lib/python/pyprimtypes.swg @@ -12,6 +12,8 @@ SWIGINTERNINLINE PyObject* } } +#ifdef SWIG_PYTHON_LEGACY_BOOL +// Default prior to SWIG 3.0.0 %fragment(SWIG_AsVal_frag(bool),"header", fragment=SWIG_AsVal_frag(long)) { SWIGINTERN int @@ -24,6 +26,23 @@ SWIG_AsVal_dec(bool)(PyObject *obj, bool *val) return SWIG_OK; } } +#else +%fragment(SWIG_AsVal_frag(bool),"header", + fragment=SWIG_AsVal_frag(long)) { +SWIGINTERN int +SWIG_AsVal_dec(bool)(PyObject *obj, bool *val) +{ + int r; + if (!PyBool_Check(obj)) + return SWIG_ERROR; + r = PyObject_IsTrue(obj); + if (r == -1) + return SWIG_ERROR; + if (val) *val = r ? true : false; + return SWIG_OK; +} +} +#endif /* int */ diff --git a/Lib/python/pytypemaps.swg b/Lib/python/pytypemaps.swg index 5c6abb01e..2341980f2 100644 --- a/Lib/python/pytypemaps.swg +++ b/Lib/python/pytypemaps.swg @@ -5,9 +5,11 @@ /* ------------------------------------------------------------ * Fragment section * ------------------------------------------------------------ */ -/* bool is dangerous in Python, change precedence */ +#ifdef SWIG_PYTHON_LEGACY_BOOL +// Default prior to SWIG 3.0.0 #undef SWIG_TYPECHECK_BOOL %define SWIG_TYPECHECK_BOOL 10000 %enddef +#endif /* Include fundamental fragment definitions */ %include