Change in default behaviour wrapping C++ bool for Python.
Only a Python True or False will now work for C++ bool parameters. This fixes overloading bool with other types.
This commit is contained in:
parent
7f45cbd178
commit
504c2030bb
11 changed files with 251 additions and 11 deletions
|
|
@ -5,6 +5,62 @@ See the RELEASENOTES file for a summary of changes in each release.
|
||||||
Version 3.0.0 (in progress)
|
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 "<stdin>", line 1, in <module>
|
||||||
|
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
|
2014-03-06: wsfulton
|
||||||
Fix SF Bug #1363 - Problem with method overloading when some methods are added by %extend
|
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.
|
and others are real methods and using template default parameters with smart pointers.
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ CPP_TEST_CASES += \
|
||||||
operator_pointer_ref \
|
operator_pointer_ref \
|
||||||
operbool \
|
operbool \
|
||||||
ordering \
|
ordering \
|
||||||
|
overload_bool \
|
||||||
overload_copy \
|
overload_copy \
|
||||||
overload_extend \
|
overload_extend \
|
||||||
overload_method \
|
overload_method \
|
||||||
|
|
|
||||||
19
Examples/test-suite/overload_bool.i
Normal file
19
Examples/test-suite/overload_bool.i
Normal file
|
|
@ -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"; }
|
||||||
|
%}
|
||||||
|
|
@ -17,10 +17,10 @@ halve_in_place(dv)
|
||||||
|
|
||||||
|
|
||||||
bv = BoolVector(4)
|
bv = BoolVector(4)
|
||||||
bv[0]= 1
|
bv[0]= bool(1)
|
||||||
bv[1]= 0
|
bv[1]= bool(0)
|
||||||
bv[2]= 4
|
bv[2]= bool(4)
|
||||||
bv[3]= 0
|
bv[3]= bool(0)
|
||||||
|
|
||||||
if bv[0] != bv[2]:
|
if bv[0] != bv[2]:
|
||||||
raise RuntimeError,"bad std::vector<bool> mapping"
|
raise RuntimeError,"bad std::vector<bool> mapping"
|
||||||
|
|
|
||||||
55
Examples/test-suite/python/overload_bool_runme.py
Normal file
55
Examples/test-suite/python/overload_bool_runme.py
Normal file
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ if ref_float(3.5) != 3.5:
|
||||||
if ref_double(3.5) != 3.5:
|
if ref_double(3.5) != 3.5:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
if ref_bool(1) != 1:
|
if ref_bool(True) != True:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
if ref_char('x') != 'x':
|
if ref_char('x') != 'x':
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ if getconstTC().num != 33:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
# primitive reference variables
|
# primitive reference variables
|
||||||
cvar.var_bool = createref_bool(0)
|
cvar.var_bool = createref_bool(False)
|
||||||
if value_bool(cvar.var_bool) != 0:
|
if value_bool(cvar.var_bool) != False:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
cvar.var_bool = createref_bool(1)
|
cvar.var_bool = createref_bool(True)
|
||||||
if value_bool(cvar.var_bool) != 1:
|
if value_bool(cvar.var_bool) != True:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
cvar.var_char = createref_char('w')
|
cvar.var_char = createref_char('w')
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ for i in range(0,len(m)):
|
||||||
if m[i][j] != im[i][j]:
|
if m[i][j] != im[i][j]:
|
||||||
raise RuntimeError, "bad getslice"
|
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)
|
im = std_containers.midentb(m)
|
||||||
for i in range(0,len(m)):
|
for i in range(0,len(m)):
|
||||||
for j in range(0,len(m[i])):
|
for j in range(0,len(m[i])):
|
||||||
|
|
|
||||||
88
Examples/test-suite/ruby/overload_bool_runme.rb
Executable file
88
Examples/test-suite/ruby/overload_bool_runme.rb
Executable file
|
|
@ -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
|
||||||
|
|
@ -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(bool),"header",
|
||||||
fragment=SWIG_AsVal_frag(long)) {
|
fragment=SWIG_AsVal_frag(long)) {
|
||||||
SWIGINTERN int
|
SWIGINTERN int
|
||||||
|
|
@ -24,6 +26,23 @@ SWIG_AsVal_dec(bool)(PyObject *obj, bool *val)
|
||||||
return SWIG_OK;
|
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 */
|
/* int */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@
|
||||||
/* ------------------------------------------------------------
|
/* ------------------------------------------------------------
|
||||||
* Fragment section
|
* 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
|
#undef SWIG_TYPECHECK_BOOL
|
||||||
%define SWIG_TYPECHECK_BOOL 10000 %enddef
|
%define SWIG_TYPECHECK_BOOL 10000 %enddef
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Include fundamental fragment definitions */
|
/* Include fundamental fragment definitions */
|
||||||
%include <typemaps/fragments.swg>
|
%include <typemaps/fragments.swg>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue