8000 Method Default Arguments by fdanny · Pull Request #87 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Method Default Arguments #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 4, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
initial changes to add default arguments
  • Loading branch information
fdanny committed Jul 31, 2015
commit 686385cdac5b0613174739607fd1aef90f817431
26 changes: 25 additions & 1 deletion src/runtime/classobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -234,13 +233,38 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
free = true;
}

// Add args given from caller
int i = Runtime.PyTuple_Size(args);
IntPtr real = Runtime.PyTuple_New(i + 1);
for (int n = 0; n < i; n++) {
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Runtime.Incref(item);
Runtime.PyTuple_SetItem(real, n, item);
}

// Do we need default arguments added to the list
if (cls.indexer.NeedsDefaultArgs(ob, real)) {
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(ob, real);
int sizeOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
int temp = i + sizeOfDefaultArgs;
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);
}

for (int n = 0; n < sizeOfDefaultArgs; n++) {

IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
Runtime.Incref(item);
Runtime.PyTuple_SetItem(real, n + i, item);
}

i = temp;
}

// Add value to argument list
Runtime.Incref(v);
Runtime.PyTuple_SetItem(real, i, v);

Expand Down
56 changes: 55 additions & 1 deletion src/runtime/indexer.cs
for (int v = pynargs; v < clrnargs; v++){
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,61 @@ internal void SetItem(IntPtr inst, IntPtr args) {
SetterBinder.Invoke(inst, args, IntPtr.Zero);
}

}
internal bool NeedsDefaultArgs(IntPtr inst, IntPtr args){
int pynargs = Runtime.PyTuple_Size(args) - 1;
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)
return false;

if (pi[v].DefaultValue == DBNull.Value)
return false;
}
return true;
}

internal IntPtr GetDefaultArgs(IntPtr inst, IntPtr args){
//IntPtr real = Runtime.PyTuple_New(i + 1);
int pynargs = Runtime.PyTuple_Size(args) - 1;
var methods = SetterBinder.GetMethods();
IntPtr defaultArgs;
if(methods.Length == 0){
defaultArgs = Runtime.PyTuple_New(0);
return defaultArgs;
}
MethodBase mi = methods[0];
ParameterInfo[] pi = mi.GetParameters();
int clrnargs = pi.Length - 1;
if(pynargs == clrnargs|| pynargs > clrnargs){
defaultArgs = Runtime.PyTuple_New(0);
return defaultArgs;
}

defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs);
for (int i = 0; i < (clrnargs - pynargs); i++) {
// Here we own the reference to the Python value, and we
// give the ownership to the arg tuple.
if (pi[i + pynargs].DefaultValue == DBNull.Value)
continue;
else{
IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType);
Type type = typeof(String);
Object arg2;
Converter.ToManaged(arg, type, out arg2, false);
Runtime.PyTuple_SetItem(defaultArgs, i, arg);
}
}
return defaultArgs;
}


}

}
71 changes: 47 additions & 24 deletions src/runtime/methodbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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) {
Expand Down
17 changes: 17 additions & 0 deletions src/testing/indexertest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

}




Expand Down
10 changes: 10 additions & 0 deletions src/testing/methodtest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/tests/test_indexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# ===========================================================================

import sys, os, string, unittest, types
import clr
clr.AddReference("Python.Test")
import Python.Test as Test
import six

Expand Down Expand Up @@ -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):
Expand Down
Loading
0