Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Don't always use "*args" for all Python wrapper functions. #201

Merged
merged 5 commits into from

2 participants

VZ William S Fulton
VZ
Owner

Due to what seems like a bug introduced during Python 3 support merge, all the
generated Python functions used the general "*args" signature instead of using
the named parameters when possible.

This happened due to is_primitive_defaultargs() always returning false for the
functions without any default arguments as "value" passed to convertValue()
was NULL in this case and convertValue() always returns false for NULL.

Fix this by checking for value being non-NULL before calling convertValue().

And also check for INOUT parameters for which we do need to use "*args" as we
don't have any name for them. Finally, rename the function to reflect that it
does more than just check for the default arguments now.

VZ vadz Remove long line wrapping from Python parameter list generation code.
This doesn't play well with PEP8 checks which imposes very strict continuation
line indentation rules which need to be _visually_ aligned, i.e. the subsequent
lines must be indented by the position of the opening bracket in the function
declaration line, but the code generating the parameter lists doesn't have
this information and so it's impossible to do it while avoiding either E128 or
E123 ("continuation line {under,over}-indented for visual indent" respectively)
error from pep8.

Moreover, the wrapping code didn't work correctly anyhow as it only took into
account the length of the parameter list itself and not the total line length,
which should include the function name as well.

So just disable wrapping entirely, long lines shouldn't be a problem anyhow in
auto-generated code.
07e2568
VZ
Owner

Note that the Travis error is an internal g++ compiler error in Octave build, so it is completely unrelated to my changes and seems to be bogus.

William S Fulton
Owner

Apart from the special handling of certain named typemaps, like INOUT, this is okay. Can you please change the parameter name checking with what we have in the strongly typed languages. Use makeParameterName() from java.cxx or csharp.cxx to ensure a valid parameter name is created, then you won't need to put in the special handling for empty and duplicate parameter names.

VZ
Owner

I thought about this, but what would be the point, actually? If there is no name, there can't be any documentation for the parameter in the first place. Is having def func(arg1, arg2, arg3): in Python really better than the current def func(*args):? The only benefit I see is that you still know that it takes just 3 arguments, but this doesn't really help when you still don't know what these arguments are...

William S Fulton
Owner

All the other parameters (that aren't OUTPUT) will have their names shown, so that is one reason to just replace the OUTPUT with an argx name.

I'd rather not have special name parameter handling. Currently, the implementation allows for a user to use any duplicate name they like and it will work with *args. We may as well helpfully 'fix' this like we do in Java/C#/D etc. If someone wants a decent name, they can provide one and use %apply instead.

Indeed, if there is no parameter then generating argx isn't helpful, but often just one argument in a list does not have a name (such as when it is for future use or deprecated). I think it would then be preferable to have the argument names and documentation appear for the remaining arguments rather than lose all this info just because of one unnamed argument.

VZ
Owner

OK, working on this.

P.S. I'd like to start by factoring out makeParameterName() to Language itself, I don't want to make another copy of it for Python it would be the fifth one (already used in C#, D, Java and Modula3).

William S Fulton
Owner

Thanks, yes. Hopefully all of them are identical.

VZ
Owner

I'm testing my changes and while they do seem to work, makeParameterName() doesn't seem to do anything special for INOUT and friends, i.e. they're still used as is in Python if there is only one parameter with such name. Do you really want to keep it like this or should I update the (thankfully unique copy of) makeParameterName() to also use argN for these special parameters for all languages?

VZ
Owner

OK, it took me much longer than I thought it would because of the keyword arguments complications, but finally things seem to work, so I'm pushing the new version.

This still doesn't rename INOUT &c to something sensible as it should, please let me know if you'd like to change this.

Also, while we now have Language::makeParameterName(), there is also, as it turns out, Swig_name_make() which seems to be used for about the same thing in some language modules (notably Ruby which contains code apparently copied from Python and which probably needs to be updated as well -- but this will be left for another day...).

vadz added some commits
VZ vadz Refactor: move makeParameterName() to common Language base class.
This method was duplicated more or less identically for 4 languages and will
be needed for another one soon, so put it in the base class from which it can
be simply reused instead.

No changes in the program behaviour whatsoever.
9f1af89
VZ vadz No real changes, just make PYTHON::check_kwargs() const.
This will allow calling it from const methods too.
80a72d5
VZ vadz Don't always use "*args" for all Python wrapper functions.
Due to what seems like a bug introduced during Python 3 support merge, all the
generated Python functions used the general "*args" signature instead of using
the named parameters when possible.

This happened due to is_primitive_defaultargs() always returning false for the
functions without any default arguments as "value" passed to convertValue()
was NULL in this case and convertValue() always returns false for NULL.

Fix this by checking for value being non-NULL before calling convertValue().

Doing this exposed several problems with the handling of unnamed, duplicate
(happens for parameters called INOUT, for example) or clashing with keywords
parameter names, so the code dealing with them had to be fixed too. Basically
just use makeParameterName() consistently everywhere.
fdc6bbe
VZ vadz Allow using enum elements as default values for Python functions.
Enum values are just (integer) constants in Python and so can be used as the
function default values just as well as literal numbers, account for this when
checking whether function parameters can be represented in Python.

Also rename is_primitive_defaultargs() to is_representable_as_pyargs() to
describe better what this function does.
15b3690
VZ
Owner

FYI: these commits are also part of PR #170 so if you can merge that one directly, this would be perfect. Otherwise I'll just rebase on latest master once this one is merged, of course. TIA!

William S Fulton
Owner

I only want doxygen changes merged in by the doxygen branch and this patch should be committed separately.

Is this patch complete now? I think there was discussion on swig-devel about it not working with some Python command line options??

VZ
Owner

This patch is complete.

The -builtin discussion was about another patch (enums, not submitted yet) and this one should work with it, although I haven't tested it. It would probably be useful to add a test suite run using this switch to Travis...

VZ
Owner

Just FYI, I've tried running the test suite on master with SWIG_FEATURES=-builtin and there are plenty of errors (without this patch), so it's difficult to test if this doesn't break something when -builtin is used. But, frankly, considering the current state, I don't think it matters.

William S Fulton
Owner

I have now sorted out the -builtin tests. Travis has two new builds:

SWIGLANG=python SWIG_FEATURES=-builtin
SWIGLANG=python SWIG_FEATURES=-builtin PY3=3

I've been meaning to do this for ages and so have finally done it. I also intend to add in a python -O test-suite

William S Fulton wsfulton merged commit 15b3690 into from
William S Fulton wsfulton referenced this pull request from a commit
William S Fulton wsfulton Fix autodoc testcase for new named python arguments when using python…
… -builtin

For the changes in #201.
5d71f91
William S Fulton wsfulton referenced this pull request from a commit
William S Fulton wsfulton Fix when is 'self' used as a parameter name in Python
Fix corner case for variable names called 'self' after merging in patch #201
a6efdb7
William S Fulton
Owner

Regarding INOUT, the patch does correct the names. This works:

//%feature("kwargs");

%include <typemaps.i>

%apply int& INOUT {int &one, int &two};
%{
void thing(int& one, int& two) {
  one = one + 1;
  two = two + 2;
}
%}
void thing(int& INOUT, int& INOUT);

But does fail (as it always did) when the kwargs line is uncommented.

VZ vadz deleted the branch
William S Fulton
Owner

'self' as a parameter name finally fixed in 6029b2f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 10, 2014
  1. VZ

    Remove long line wrapping from Python parameter list generation code.

    vadz authored
    This doesn't play well with PEP8 checks which imposes very strict continuation
    line indentation rules which need to be _visually_ aligned, i.e. the subsequent
    lines must be indented by the position of the opening bracket in the function
    declaration line, but the code generating the parameter lists doesn't have
    this information and so it's impossible to do it while avoiding either E128 or
    E123 ("continuation line {under,over}-indented for visual indent" respectively)
    error from pep8.
    
    Moreover, the wrapping code didn't work correctly anyhow as it only took into
    account the length of the parameter list itself and not the total line length,
    which should include the function name as well.
    
    So just disable wrapping entirely, long lines shouldn't be a problem anyhow in
    auto-generated code.
Commits on Aug 16, 2014
  1. VZ

    Refactor: move makeParameterName() to common Language base class.

    vadz authored
    This method was duplicated more or less identically for 4 languages and will
    be needed for another one soon, so put it in the base class from which it can
    be simply reused instead.
    
    No changes in the program behaviour whatsoever.
  2. VZ

    No real changes, just make PYTHON::check_kwargs() const.

    vadz authored
    This will allow calling it from const methods too.
  3. VZ

    Don't always use "*args" for all Python wrapper functions.

    vadz authored
    Due to what seems like a bug introduced during Python 3 support merge, all the
    generated Python functions used the general "*args" signature instead of using
    the named parameters when possible.
    
    This happened due to is_primitive_defaultargs() always returning false for the
    functions without any default arguments as "value" passed to convertValue()
    was NULL in this case and convertValue() always returns false for NULL.
    
    Fix this by checking for value being non-NULL before calling convertValue().
    
    Doing this exposed several problems with the handling of unnamed, duplicate
    (happens for parameters called INOUT, for example) or clashing with keywords
    parameter names, so the code dealing with them had to be fixed too. Basically
    just use makeParameterName() consistently everywhere.
  4. VZ

    Allow using enum elements as default values for Python functions.

    vadz authored
    Enum values are just (integer) constants in Python and so can be used as the
    function default values just as well as literal numbers, account for this when
    checking whether function parameters can be represented in Python.
    
    Also rename is_primitive_defaultargs() to is_representable_as_pyargs() to
    describe better what this function does.
This page is out of date. Refresh to see the latest.
3  Examples/test-suite/python/default_args_runme.py
View
@@ -1,5 +1,8 @@
import default_args
+ec = default_args.EnumClass()
+if not ec.blah():
+ raise RuntimeError,"EnumClass::blah() default arguments don't work"
if default_args.Statics_staticMethod() != 60:
raise RuntimeError
37 Source/Modules/csharp.cxx
View
@@ -3201,43 +3201,6 @@ class CSHARP:public Language {
}
/* -----------------------------------------------------------------------------
- * makeParameterName()
- *
- * Inputs:
- * n - Node
- * p - parameter node
- * arg_num - parameter argument number
- * setter - set this flag when wrapping variables
- * Return:
- * arg - a unique parameter name
- * ----------------------------------------------------------------------------- */
-
- String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) {
-
- String *arg = 0;
- String *pn = Getattr(p, "name");
-
- // Use C parameter name unless it is a duplicate or an empty parameter name
- int count = 0;
- ParmList *plist = Getattr(n, "parms");
- while (plist) {
- if ((Cmp(pn, Getattr(plist, "name")) == 0))
- count++;
- plist = nextSibling(plist);
- }
- String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0;
- arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn);
-
- if (setter && Cmp(arg, "self") != 0) {
- // Note that in C# properties, the input variable name is always called 'value'
- Delete(arg);
- arg = NewString("value");
- }
-
- return arg;
- }
-
- /* -----------------------------------------------------------------------------
* emitTypeWrapperClass()
* ----------------------------------------------------------------------------- */
34 Source/Modules/d.cxx
View
@@ -4299,40 +4299,8 @@ class D : public Language {
return proxyname;
}
- /* ---------------------------------------------------------------------------
- * D::makeParameterName()
- *
- * Inputs:
- * n - Node
- * p - parameter node
- * arg_num - parameter argument number
- * setter - set this flag when wrapping variables
- * Return:
- * arg - a unique parameter name
- * --------------------------------------------------------------------------- */
String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const {
- String *arg = 0;
- String *pn = Getattr(p, "name");
-
- // Use C parameter name unless it is a duplicate or an empty parameter name
- int count = 0;
- ParmList *plist = Getattr(n, "parms");
- while (plist) {
- if ((Cmp(pn, Getattr(plist, "name")) == 0))
- count++;
- plist = nextSibling(plist);
- }
- String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0;
- arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn);
-
- if (setter && Cmp(arg, "self") != 0) {
- // In theory, we could use the normal parameter name for setter functions.
- // Unfortunately, it is set to "Class::VariableName" for static public
- // members by the parser, which is not legal D syntax. Thus, we just force
- // it to "value".
- Delete(arg);
- arg = NewString("value");
- }
+ String *arg = Language::makeParameterName(n, p, arg_num, setter);
if (split_proxy_dmodule && Strncmp(arg, package, Len(arg)) == 0) {
// If we are in split proxy mode and the argument is named like the target
38 Source/Modules/java.cxx
View
@@ -3116,44 +3116,6 @@ class JAVA:public Language {
}
/* -----------------------------------------------------------------------------
- * makeParameterName()
- *
- * Inputs:
- * n - Node
- * p - parameter node
- * arg_num - parameter argument number
- * setter - set this flag when wrapping variables
- * Return:
- * arg - a unique parameter name
- * ----------------------------------------------------------------------------- */
-
- String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) {
-
- String *arg = 0;
- String *pn = Getattr(p, "name");
-
- // Use C parameter name unless it is a duplicate or an empty parameter name
- int count = 0;
- ParmList *plist = Getattr(n, "parms");
- while (plist) {
- if ((Cmp(pn, Getattr(plist, "name")) == 0))
- count++;
- plist = nextSibling(plist);
- }
- String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0;
- arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn);
-
- if (setter && Cmp(arg, "self") != 0) {
- // Note that for setters the parameter name is always set but sometimes includes C++
- // scope resolution, so we need to strip off the scope resolution to make a valid name.
- Delete(arg);
- arg = NewString("value"); //Swig_scopename_last(pn);
- }
-
- return arg;
- }
-
- /* -----------------------------------------------------------------------------
* emitTypeWrapperClass()
* ----------------------------------------------------------------------------- */
38 Source/Modules/lang.cxx
View
@@ -3500,6 +3500,44 @@ int Language::is_smart_pointer() const {
}
/* -----------------------------------------------------------------------------
+ * Language::makeParameterName()
+ *
+ * Inputs:
+ * n - Node
+ * p - parameter node
+ * arg_num - parameter argument number
+ * setter - set this flag when wrapping variables
+ * Return:
+ * arg - a unique parameter name
+ * ----------------------------------------------------------------------------- */
+String *Language::makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const {
+
+ String *arg = 0;
+ String *pn = Getattr(p, "name");
+
+ // Use C parameter name unless it is a duplicate or an empty parameter name
+ int count = 0;
+ ParmList *plist = Getattr(n, "parms");
+ while (plist) {
+ if ((Cmp(pn, Getattr(plist, "name")) == 0))
+ count++;
+ plist = nextSibling(plist);
+ }
+ String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0;
+ arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn);
+
+ if (setter && Cmp(arg, "self") != 0) {
+ // Some languages (C#) insist on calling the input variable "value" while
+ // others (D, Java) could, in principle, use something different but this
+ // would require more work, and so we just use "value" for them too.
+ Delete(arg);
+ arg = NewString("value");
+ }
+
+ return arg;
+}
+
+/* -----------------------------------------------------------------------------
* Language::()
* ----------------------------------------------------------------------------- */
29 Source/Modules/modula3.cxx
View
@@ -3622,35 +3622,6 @@ MODULA3():
}
/* -----------------------------------------------------------------------------
- * makeParameterName()
- *
- * Inputs:
- * n - Node
- * p - parameter node
- * arg_num - parameter argument number
- * Return:
- * arg - a unique parameter name
- * ----------------------------------------------------------------------------- */
-
- String *makeParameterName(Node *n, Parm *p, int arg_num) {
-
- // Use C parameter name unless it is a duplicate or an empty parameter name
- String *pn = Getattr(p, "name");
- int count = 0;
- ParmList *plist = Getattr(n, "parms");
- while (plist) {
- if ((Cmp(pn, Getattr(plist, "name")) == 0))
- count++;
- plist = nextSibling(plist);
- }
- String *arg = (!pn || (count > 1)) ? NewStringf("arg%d",
- arg_num) : Copy(Getattr(p,
- "name"));
-
- return arg;
- }
-
- /* -----------------------------------------------------------------------------
* attachParameterNames()
*
* Inputs:
152 Source/Modules/python.cxx
View
@@ -1523,6 +1523,21 @@ class PYTHON:public Language {
return ds;
}
+ virtual String *makeParameterName(Node *n, Parm *p, int arg_num, bool = false) const {
+ // For the keyword arguments, we want to preserve the names as much as possible,
+ // so we only minimally rename them in Swig_name_make(), e.g. replacing "keyword"
+ // with "_keyword" if they have any name at all.
+ if (check_kwargs(n)) {
+ String* name = Getattr(p, "name");
+ if (name)
+ return Swig_name_make(p, 0, name, 0, 0);
+ }
+
+ // For the other cases use the general function which replaces arguments whose
+ // names clash with keywords with (less useful) "argN".
+ return Language::makeParameterName(n, p, arg_num);
+ }
+
/* -----------------------------------------------------------------------------
* addMissingParameterNames()
* For functions that have not had nameless parameters set in the Language class.
@@ -1534,13 +1549,14 @@ class PYTHON:public Language {
* The "lname" attribute in each parameter in plist will be contain a parameter name
* ----------------------------------------------------------------------------- */
- void addMissingParameterNames(ParmList *plist, int arg_offset) {
+ void addMissingParameterNames(Node* n, ParmList *plist, int arg_offset) {
Parm *p = plist;
int i = arg_offset;
while (p) {
if (!Getattr(p, "lname")) {
- String *pname = Swig_cparm_name(p, i);
- Delete(pname);
+ String *name = makeParameterName(n, p, i);
+ Setattr(p, "lname", name);
+ Delete(name);
}
i++;
p = nextSibling(p);
@@ -1563,14 +1579,18 @@ class PYTHON:public Language {
Parm *pnext;
- int lines = 0;
- int start_arg_num = is_wrapping_class() ? 1 : 0;
- const int maxwidth = 80;
+ // Normally we start counting auto-generated argument names from 1, but we should do it from 2
+ // if the first argument is "self", i.e. if we're handling a non-static member function.
+ int arg_num = 1;
+ if (is_wrapping_class()) {
+ if (Cmp(Getattr(n, "storage"), "static") != 0)
+ arg_num++;
+ }
if (calling)
func_annotation = false;
- addMissingParameterNames(plist, start_arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms
+ addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms
Swig_typemap_attach_parms("in", plist, 0);
Swig_typemap_attach_parms("doc", plist, 0);
@@ -1579,7 +1599,7 @@ class PYTHON:public Language {
return doc;
}
- for (p = plist; p; p = pnext) {
+ for (p = plist; p; p = pnext, arg_num++) {
String *tm = Getattr(p, "tmap:in");
if (tm) {
@@ -1602,25 +1622,22 @@ class PYTHON:public Language {
}
// Note: the generated name should be consistent with that in kwnames[]
- name = name ? name : Getattr(p, "name");
- name = name ? name : Getattr(p, "lname");
- name = Swig_name_make(p, 0, name, 0, 0); // rename parameter if a keyword
+ String *made_name = 0;
+ if (!name) {
+ name = made_name = makeParameterName(n, p, arg_num);
+ }
type = type ? type : Getattr(p, "type");
value = value ? value : Getattr(p, "value");
- if (SwigType_isvarargs(type))
+ if (SwigType_isvarargs(type)) {
+ Delete(made_name);
break;
+ }
if (Len(doc)) {
// add a comma to the previous one if any
Append(doc, ", ");
-
- // Do we need to wrap a long line?
- if ((Len(doc) - lines * maxwidth) > maxwidth) {
- Printf(doc, "\n%s", tab4);
- lines += 1;
- }
}
// Do the param type too?
@@ -1642,17 +1659,11 @@ class PYTHON:public Language {
// Write default value
if (value && !calling) {
String *new_value = convertValue(value, Getattr(p, "type"));
- if (new_value) {
- value = new_value;
- } else {
- Node *lookup = Swig_symbol_clookup(value, 0);
- if (lookup)
- value = Getattr(lookup, "sym:name");
- }
- Printf(doc, "=%s", value);
+ if (new_value)
+ Printf(doc, "=%s", new_value);
}
Delete(type_str);
- Delete(name);
+ Delete(made_name);
}
if (pdocs)
Setattr(n, "feature:pdocs", pdocs);
@@ -1800,40 +1811,50 @@ class PYTHON:public Language {
/* ------------------------------------------------------------
* convertValue()
- * Check if string v can be a Python value literal,
- * (eg. number or string), or translate it to a Python literal.
+ * Check if string v can be a Python value literal or a
+ * constant. Return NIL if it isn't.
* ------------------------------------------------------------ */
String *convertValue(String *v, SwigType *t) {
- if (v && Len(v) > 0) {
- char fc = (Char(v))[0];
- if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) {
- /* number or string (or maybe NULL pointer) */
- if (SwigType_ispointer(t) && Strcmp(v, "0") == 0)
- return NewString("None");
- else
- return v;
- }
- if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
- return NewString("True");
- if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
- return NewString("False");
- if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
- return SwigType_ispointer(t) ? NewString("None") : NewString("0");
+ char fc = (Char(v))[0];
+ if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) {
+ /* number or string (or maybe NULL pointer) */
+ if (SwigType_ispointer(t) && Strcmp(v, "0") == 0)
+ return NewString("None");
+ else
+ return v;
}
- return 0;
+ if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
+ return NewString("True");
+ if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
+ return NewString("False");
+ if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
+ return SwigType_ispointer(t) ? NewString("None") : NewString("0");
+
+ // This could also be an enum type, default value of which is perfectly
+ // representable in Python.
+ Node *lookup = Swig_symbol_clookup(v, 0);
+ if (lookup) {
+ if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0)
+ return Getattr(lookup, "sym:name");
+ }
+
+ return NIL;
}
+
/* ------------------------------------------------------------
- * is_primitive_defaultargs()
- * Check if all the default args have primitive type.
- * (So we can generate proper parameter list with default
- * values..)
+ * is_representable_as_pyargs()
+ * Check if the function parameters default argument values
+ * can be represented in Python.
+ *
+ * If this method returns false, the parameters will be translated
+ * to a generic "*args" which allows us to deal with default values
+ * at C++ code level where they can always be handled.
* ------------------------------------------------------------ */
- bool is_primitive_defaultargs(Node *n) {
+ bool is_representable_as_pyargs(Node *n) {
ParmList *plist = CopyParmList(Getattr(n, "parms"));
Parm *p;
Parm *pnext;
- Swig_typemap_attach_parms("in", plist, 0);
for (p = plist; p; p = pnext) {
String *tm = Getattr(p, "tmap:in");
if (tm) {
@@ -1844,10 +1865,11 @@ class PYTHON:public Language {
} else {
pnext = nextSibling(p);
}
- String *type = Getattr(p, "type");
- String *value = Getattr(p, "value");
- if (!convertValue(value, type))
- return false;
+ if (String *value = Getattr(p, "value")) {
+ String *type = Getattr(p, "type");
+ if (!convertValue(value, type))
+ return false;
+ }
}
return true;
}
@@ -1892,7 +1914,7 @@ class PYTHON:public Language {
n = nn;
/* For overloaded function, just use *args */
- if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || !is_primitive_defaultargs(n)) {
+ if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || !is_representable_as_pyargs(n)) {
String *parms = NewString("");
if (in_class)
Printf(parms, "self, ");
@@ -2052,7 +2074,7 @@ class PYTHON:public Language {
* check if using kwargs is allowed for this Node
* ------------------------------------------------------------ */
- int check_kwargs(Node *n) {
+ int check_kwargs(Node *n) const {
return (use_kw || GetFlag(n, "feature:kwargs"))
&& !GetFlag(n, "memberset") && !GetFlag(n, "memberget");
}
@@ -2431,7 +2453,6 @@ class PYTHON:public Language {
}
SwigType *pt = Getattr(p, "type");
- String *pn = Getattr(p, "name");
String *ln = Getattr(p, "lname");
bool parse_from_tuple = (i > 0 || !add_self);
if (SwigType_type(pt) == T_VARARGS) {
@@ -2453,18 +2474,9 @@ class PYTHON:public Language {
/* Keyword argument handling */
if (allow_kwargs && parse_from_tuple) {
- if (Len(pn)) {
- String *tmp = 0;
- String *name = pn;
- if (!Getattr(p, "hidden")) {
- name = tmp = Swig_name_make(p, 0, pn, 0, 0); // rename parameter if a keyword
- }
- Printf(kwargs, "(char *) \"%s\",", name);
- if (tmp)
- Delete(tmp);
- } else {
- Printf(kwargs, "(char *)\"arg%d\",", i + 1);
- }
+ String *name = makeParameterName(n, p, i + 1);
+ Printf(kwargs, "(char *) \"%s\",", name);
+ Delete(name);
}
/* Look for an input typemap */
3  Source/Modules/swigmod.h
View
@@ -297,6 +297,9 @@ class Language:public Dispatcher {
/* Return true if the current method is part of a smart-pointer */
int is_smart_pointer() const;
+ /* Return the name to use for the given parameter. */
+ virtual String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter = false) const;
+
/* Some language modules require additional wrappers for virtual methods not declared in sub-classes */
virtual bool extraDirectorProtectedCPPMethodsRequired() const;
Something went wrong with that request. Please try again.