Fix Python default argument handing broken since swig-3.0.3
Default values are no longer generated as Python code by default. They must be explicitly turned on using the "python:defaultargs" feature. Closes #294 Closes #296 The problems in these two issues when "python:defaultargs" is turned on still need to be fixed and should be addressed in separate patches. The important thing is the default code generation is now fixed.
This commit is contained in:
parent
34787ab98e
commit
38ba81811e
8 changed files with 139 additions and 69 deletions
|
|
@ -5,6 +5,16 @@ See the RELEASENOTES file for a summary of changes in each release.
|
||||||
Version 3.0.4 (in progress)
|
Version 3.0.4 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2015-01-08: wsfulton
|
||||||
|
[Python] Fix #294 #296 - Regression introduced in SWIG-3.0.3 when
|
||||||
|
wrapping functions with default arguments. Now any method with default
|
||||||
|
arguments obtains the default arguments from C++ instead of generating
|
||||||
|
Python code with the default arguments.
|
||||||
|
|
||||||
|
The "python:defaultargs" feature has been introduced for users to
|
||||||
|
optionally generate Python methods with the default arguments instead
|
||||||
|
the default *args.
|
||||||
|
|
||||||
2015-01-08: olly
|
2015-01-08: olly
|
||||||
Allow C++11 "explicit constexpr". Fixes github issue#284 reported
|
Allow C++11 "explicit constexpr". Fixes github issue#284 reported
|
||||||
by Paweł Tomulik. Also handle "constexpr explicit" and "constexpr
|
by Paweł Tomulik. Also handle "constexpr explicit" and "constexpr
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// All kinds of numbers: hex, octal (which pose special problems to Python), negative...
|
// All kinds of numbers: hex, octal (which pose special problems to Python), negative...
|
||||||
void lots_of_args(int pos = -1, unsigned rgb = 0xabcdef, int mode = 0644) { }
|
void trickyvalue1(int first, int pos = -1) {}
|
||||||
|
void trickyvalue2(int first, unsigned rgb = 0xabcdef) {}
|
||||||
|
void trickyvalue3(int first, int mode = 0644) {}
|
||||||
|
|
||||||
// Long long arguments are not handled at Python level currently but still work.
|
// Long long arguments are not handled at Python level currently but still work.
|
||||||
void seek(long long offset = 0LL) {}
|
void seek(long long offset = 0LL) {}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ CPP_TEST_CASES += \
|
||||||
primitive_types \
|
primitive_types \
|
||||||
python_abstractbase \
|
python_abstractbase \
|
||||||
python_append \
|
python_append \
|
||||||
|
python_default_args \
|
||||||
python_director \
|
python_director \
|
||||||
python_nondynamic \
|
python_nondynamic \
|
||||||
python_overload_simple_cast \
|
python_overload_simple_cast \
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
import default_args
|
# Note that this test is also used by python_default_args_runme.py hence the use of __main__ and the run function
|
||||||
|
|
||||||
|
def run(module_name):
|
||||||
|
default_args = __import__(module_name)
|
||||||
|
print "running...."
|
||||||
ec = default_args.EnumClass()
|
ec = default_args.EnumClass()
|
||||||
if not ec.blah():
|
if not ec.blah():
|
||||||
raise RuntimeError,"EnumClass::blah() default arguments don't work"
|
raise RuntimeError,"EnumClass::blah() default arguments don't work"
|
||||||
|
|
||||||
|
de = default_args.DerivedEnumClass()
|
||||||
|
de.accelerate()
|
||||||
|
de.accelerate(default_args.EnumClass.SLOW)
|
||||||
|
|
||||||
if default_args.Statics_staticMethod() != 60:
|
if default_args.Statics_staticMethod() != 60:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
|
|
@ -65,3 +72,20 @@ except:
|
||||||
error = 0
|
error = 0
|
||||||
if error: raise RuntimeError,"Foo::meth ignore is not working"
|
if error: raise RuntimeError,"Foo::meth ignore is not working"
|
||||||
|
|
||||||
|
if default_args.Klass.inc(100, default_args.Klass(22)).val != 122:
|
||||||
|
raise RuntimeError, "Klass::inc failed"
|
||||||
|
|
||||||
|
if default_args.Klass.inc(100).val != 99:
|
||||||
|
raise RuntimeError, "Klass::inc failed"
|
||||||
|
|
||||||
|
if default_args.Klass.inc().val != 0:
|
||||||
|
raise RuntimeError, "Klass::inc failed"
|
||||||
|
|
||||||
|
default_args.trickyvalue1(10); default_args.trickyvalue1(10, 10)
|
||||||
|
default_args.trickyvalue2(10); default_args.trickyvalue2(10, 10)
|
||||||
|
default_args.trickyvalue3(10); default_args.trickyvalue3(10, 10)
|
||||||
|
default_args.seek(); default_args.seek(10)
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
run('default_args')
|
||||||
|
|
||||||
|
|
|
||||||
3
Examples/test-suite/python/python_default_args_runme.py
Normal file
3
Examples/test-suite/python/python_default_args_runme.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Test %feature("python:defaultargs") using the test code in default_args_runme.py (which does not use the feature)
|
||||||
|
import default_args_runme
|
||||||
|
default_args_runme.run('python_default_args')
|
||||||
10
Examples/test-suite/python_default_args.i
Normal file
10
Examples/test-suite/python_default_args.i
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
%module python_default_args
|
||||||
|
|
||||||
|
%pythondefaultargs;
|
||||||
|
|
||||||
|
// Turn off the feature for the tricky cases that can't be handled
|
||||||
|
%nopythondefaultargs seek;
|
||||||
|
%nopythondefaultargs Space::Klass::inc;
|
||||||
|
%nopythondefaultargs DerivedEnumClass::accelerate;
|
||||||
|
|
||||||
|
%include "default_args.i"
|
||||||
|
|
@ -185,6 +185,16 @@ These methods "may be called" if needed.
|
||||||
#define %clearpythonappend %feature("pythonappend","")
|
#define %clearpythonappend %feature("pythonappend","")
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
Python default argument handling (for non-builtin)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define %pythondefaultargs %feature("python:defaultargs")
|
||||||
|
#define %nopythondefaultargs %feature("python:defaultargs", "0")
|
||||||
|
#define %clearpythondefaultargs %feature("python:defaultargs", "")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1856,6 +1856,10 @@ public:
|
||||||
* at C++ code level where they can always be handled.
|
* at C++ code level where they can always be handled.
|
||||||
* ------------------------------------------------------------ */
|
* ------------------------------------------------------------ */
|
||||||
bool is_representable_as_pyargs(Node *n) {
|
bool is_representable_as_pyargs(Node *n) {
|
||||||
|
bool is_representable = true;
|
||||||
|
|
||||||
|
if (Getattr(n, "sym:overloaded")) {
|
||||||
|
if (GetFlag(n, "feature:python:defaultargs")) {
|
||||||
ParmList *plist = CopyParmList(Getattr(n, "parms"));
|
ParmList *plist = CopyParmList(Getattr(n, "parms"));
|
||||||
Parm *p;
|
Parm *p;
|
||||||
Parm *pnext;
|
Parm *pnext;
|
||||||
|
|
@ -1872,11 +1876,17 @@ public:
|
||||||
}
|
}
|
||||||
if (String *value = Getattr(p, "value")) {
|
if (String *value = Getattr(p, "value")) {
|
||||||
String *type = Getattr(p, "type");
|
String *type = Getattr(p, "type");
|
||||||
if (!convertValue(value, type))
|
if (!convertValue(value, type)) {
|
||||||
return false;
|
is_representable = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
} else {
|
||||||
|
is_representable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_representable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue