diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs
index 5e79e8253..03f784ed7 100644
--- a/src/runtime/classobject.cs
+++ b/src/runtime/classobject.cs
@@ -223,7 +223,6 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
-
IntPtr args = idx;
bool free = false;
@@ -234,13 +233,29 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
free = true;
}
+ // Get the args passed in.
int i = Runtime.PyTuple_Size(args);
- IntPtr real = Runtime.PyTuple_New(i + 1);
+ IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
+ int numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
+ int temp = i + numOfDefaultArgs;
+ IntPtr real = Runtime.PyTuple_New(temp + 1);
for (int n = 0; n < i; n++) {
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Runtime.Incref(item);
Runtime.PyTuple_SetItem(real, n, item);
}
+
+ // Add Default Args if needed
+ for (int n = 0; n < numOfDefaultArgs; n++) {
+ IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
+ Runtime.Incref(item);
+ Runtime.PyTuple_SetItem(real, n + i, item);
+ }
+ // no longer need defaultArgs
+ Runtime.Decref(defaultArgs);
+ i = temp;
+
+ // Add value to argument list
Runtime.Incref(v);
Runtime.PyTuple_SetItem(real, i, v);
diff --git a/src/runtime/indexer.cs b/src/runtime/indexer.cs
index 8118dc339..0781a3a0a 100644
--- a/src/runtime/indexer.cs
+++ b/src/runtime/indexer.cs
@@ -62,7 +62,57 @@ internal void SetItem(IntPtr inst, IntPtr args) {
SetterBinder.Invoke(inst, args, IntPtr.Zero);
}
- }
+ internal bool NeedsDefaultArgs(IntPtr args){
+ int pynargs = Runtime.PyTuple_Size(args);
+ var methods = SetterBinder.GetMethods();
+ if(methods.Length == 0)
+ return false;
+
+ MethodBase mi = methods[0];
+ ParameterInfo[] pi = mi.GetParameters();
+ // need to subtract one for the value
+ int clrnargs = pi.Length - 1;
+ if (pynargs == clrnargs || pynargs > clrnargs)
+ return false;
+
+ for (int v = pynargs; v < clrnargs; v++){
+ if (pi[v].DefaultValue == DBNull.Value)
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// This will return default arguments a new instance of a tuple. The size
+ /// of the tuple will indicate the number of default arguments.
+ ///
+ /// This is pointing to the tuple args passed in
+ /// a new instance of the tuple containing the default args
+ internal IntPtr GetDefaultArgs(IntPtr args){
+
+ // if we don't need default args return empty tuple
+ if(!NeedsDefaultArgs(args))
+ return Runtime.PyTuple_New(0);
+ int pynargs = Runtime.PyTuple_Size(args);
+
+ // Get the default arg tuple
+ var methods = SetterBinder.GetMethods();
+ MethodBase mi = methods[0];
+ ParameterInfo[] pi = mi.GetParameters();
+ int clrnargs = pi.Length - 1;
+ IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs);
+ for (int i = 0; i < (clrnargs - pynargs); i++) {
+ if (pi[i + pynargs].DefaultValue == DBNull.Value)
+ continue;
+ else{
+ IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType);
+ Runtime.PyTuple_SetItem(defaultArgs, i, arg);
+ }
+ }
+ return defaultArgs;
+ }
+ }
+
}
diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs
index 80d3968fd..3b83ca379 100644
--- a/src/runtime/methodbinder.cs
+++ b/src/runtime/methodbinder.cs
@@ -226,7 +226,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
int pynargs = Runtime.PyTuple_Size(args);
object arg;
bool isGeneric = false;
-
+ ArrayList defaultArgList = null;
if (info != null) {
_methods = (MethodBase[])Array.CreateInstance(
typeof(MethodBase), 1
@@ -247,7 +247,17 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
int outs = 0;
if (pynargs == clrnargs) {
- match = true;
+ match = true;
+ } else if(pynargs < clrnargs){
+ match = true;
+ defaultArgList = new ArrayList();
+ for (int v = pynargs; v < clrnargs; v++)
+ {
+ if (pi[v].DefaultValue == DBNull.Value)
+ match = false;
+ else
+ defaultArgList.Add((object)pi[v].DefaultValue);
+ }
} else if ((pynargs > clrnargs) && (clrnargs > 0) &&
(pi[clrnargs-1].ParameterType.IsArray)) {
// The last argument of the mananged functions seems to
@@ -262,30 +272,43 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
for (int n = 0; n < clrnargs; n++) {
IntPtr op;
- if (arrayStart == n) {
- // map remaining Python arguments to a tuple since
- // the managed function accepts it - hopefully :]
- op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
- }
- else {
- op = Runtime.PyTuple_GetItem(args, n);
- }
- Type type = pi[n].ParameterType;
- if (pi[n].IsOut || type.IsByRef) {
- outs++;
- }
-
- if (!Converter.ToManaged(op, type, out arg, false)) {
- Exceptions.Clear();
- margs = null;
- break;
+ if (n < pynargs)
+ {
+ if (arrayStart == n)
+ {
+ // map remaining Python arguments to a tuple since
+ // the managed function accepts it - hopefully :]
+ op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
+ }
+ else
+ {
+ op = Runtime.PyTuple_GetItem(args, n);
+ }
+ Type type = pi[n].ParameterType;
+ if (pi[n].IsOut || type.IsByRef)
+ {
+ outs++;
+ }
+
+ if (!Converter.ToManaged(op, type, out arg, false))
+ {
+ Exceptions.Clear();
+ margs = null;
+ break;
+ }
+ if (arrayStart == n)
+ {
+ // GetSlice() creates a new reference but GetItem()
+ // returns only a borrow reference.
+ Runtime.Decref(op);
+ }
+ margs[n] = arg;
}
- if (arrayStart == n) {
- // GetSlice() creates a new reference but GetItem()
- // returns only a borrow reference.
- Runtime.Decref(op);
+ else
+ {
+ if (defaultArgList != null)
+ margs[n] = defaultArgList[n - pynargs];
}
- margs[n] = arg;
}
if (margs == null) {
diff --git a/src/testing/indexertest.cs b/src/testing/indexertest.cs
index fa4a8c8e2..7caba4e64 100644
--- a/src/testing/indexertest.cs
+++ b/src/testing/indexertest.cs
@@ -347,6 +347,23 @@ public MultiTypeIndexerTest() : base() {}
}
+ public class MultiDefaultKeyIndexerTest : IndexerBase {
+
+ public MultiDefaultKeyIndexerTest() : base() { }
+
+ public string this[int i1, int i2 = 2] {
+ get {
+ string key = i1.ToString() + i2.ToString();
+ return (string)t[key];
+ }
+ set {
+ string key = i1.ToString() + i2.ToString();
+ t[key] = value;
+ }
+ }
+
+ }
+
diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs
index 086aa58d5..8bda5215f 100644
--- a/src/testing/methodtest.cs
+++ b/src/testing/methodtest.cs
@@ -155,6 +155,16 @@ public static void TestVoidSingleRefParam (ref int i) {
i = 42;
}
+ public static int TestSingleDefaultParam(int i = 5) {
+ return i;
+ }
+ public static int TestTwoDefaultParam(int i = 5, int j = 6) {
+ return i + j;
+ }
+ public static int TestOneArgAndTwoDefaultParam(int z, int i = 5, int j = 6) {
+ return i + j + z;
+ }
+
// overload selection test support
diff --git a/src/tests/test_indexer.py b/src/tests/test_indexer.py
index cb572e3a8..691ebb871 100644
--- a/src/tests/test_indexer.py
+++ b/src/tests/test_indexer.py
@@ -8,6 +8,8 @@
# ===========================================================================
import sys, os, string, unittest, types
+import clr
+clr.AddReference("Python.Test")
import Python.Test as Test
import six
@@ -630,6 +632,17 @@ def test():
object[0, 1, spam] = "wrong"
self.assertRaises(TypeError, test)
+
+
+ def testMultiDefaultKeyIndexer(self):
+ """Test indexers that take multiple indices with a default key arguments."""
+ #default argument is 2 in the MultiDefaultKeyIndexerTest object
+ object = Test.MultiDefaultKeyIndexerTest()
+ object[0, 2] = "zero one spam"
+ self.assertTrue(object[0] == "zero one spam")
+
+ object[1] = "one nine spam"
+ self.assertTrue(object[1, 2] == "one nine spam")
def testIndexerWrongKeyType(self):
diff --git a/src/tests/test_method.py b/src/tests/test_method.py
index cdfc1e33b..3f9c1fdff 100644
--- a/src/tests/test_method.py
+++ b/src/tests/test_method.py
@@ -447,6 +447,27 @@ def test():
# None cannot be converted to a value type
self.assertRaises(TypeError, test)
+
+ def testSingleDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestSingleDefaultParam()
+ self.assertTrue(result == 5)
+
+ def testOneArgAndTwoDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestOneArgAndTwoDefaultParam(11)
+ self.assertTrue(result == 22)
+
+ result = MethodTest.TestOneArgAndTwoDefaultParam(15)
+ self.assertTrue(result == 26)
+
+ result = MethodTest.TestOneArgAndTwoDefaultParam(20)
+ self.assertTrue(result == 31)
+
+ def testTwoDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestTwoDefaultParam()
+ self.assertTrue(result == 11)
def testExplicitSelectionWithOutModifier(self):