@@ -369,6 +369,41 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
369
369
return null ;
370
370
}
371
371
372
+ static IntPtr HandleParamsArray ( IntPtr args , int arrayStart , int pyArgCount , out bool isNewReference )
373
+ {
374
+ isNewReference = false ;
375
+ IntPtr op ;
376
+ // for a params method, we may have a sequence or single/multiple items
377
+ // here we look to see if the item at the paramIndex is there or not
378
+ // and then if it is a sequence itself.
379
+ if ( ( pyArgCount - arrayStart ) == 1 )
380
+ {
381
+ // we only have one argument left, so we need to check it
382
+ // to see if it is a sequence or a single item
383
+ IntPtr item = Runtime . PyTuple_GetItem ( args , arrayStart ) ;
384
+ if ( ! Runtime . PyString_Check ( item ) && Runtime . PySequence_Check ( item ) )
385
+ {
386
+ // it's a sequence (and not a string), so we use it as the op
387
+ op = item ;
388
+ }
389
+ else
390
+ {
391
+ isNewReference = true ;
392
+ op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
393
+ if ( item != IntPtr . Zero )
394
+ {
395
+ Runtime . XDecref ( item ) ;
396
+ }
397
+ }
398
+ }
399
+ else
400
+ {
401
+ isNewReference = true ;
402
+ op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
403
+ }
404
+ return op ;
405
+ }
406
+
372
407
/// <summary>
373
408
/// Attempts to convert Python positional argument tuple and keyword argument table
374
409
/// into an array of managed objects, that can be passed to a method.
@@ -397,8 +432,9 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
397
432
{
398
433
var parameter = pi [ paramIndex ] ;
399
434
bool hasNamedParam = kwargDict . ContainsKey ( parameter . Name ) ;
435
+ bool isNewReference = false ;
400
436
401
- if ( paramIndex >= pyArgCount && ! hasNamedParam )
437
+ if ( paramIndex >= pyArgCount && ! ( hasNamedParam || ( paramsArray && paramIndex == arrayStart ) ) )
402
438
{
403
439
if ( defaultArgList != null )
404
440
{
@@ -415,11 +451,14 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
415
451
}
416
452
else
417
453
{
418
- op = ( arrayStart == paramIndex )
419
- // map remaining Python arguments to a tuple since
420
- // the managed function accepts it - hopefully :]
421
- ? Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount )
422
- : Runtime . PyTuple_GetItem ( args , paramIndex ) ;
454
+ if ( arrayStart == paramIndex )
455
+ {
456
+ op = HandleParamsArray ( args , arrayStart , pyArgCount , out isNewReference ) ;
457
+ }
458
+ else
459
+ {
460
+ op = Runtime . PyTuple_GetItem ( args , paramIndex ) ;
461
+ }
423
462
}
424
463
425
464
bool isOut ;
@@ -428,7 +467,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
428
467
return null ;
429
468
}
430
469
431
- if ( arrayStart == paramIndex )
470
+ if ( isNewReference )
432
471
{
433
472
// TODO: is this a bug? Should this happen even if the conversion fails?
434
473
// GetSlice() creates a new reference but GetItem()
@@ -543,7 +582,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
543
582
{
544
583
defaultArgList = null ;
545
584
var match = false ;
546
- paramsArray = false ;
585
+ paramsArray = parameters . Length > 0 ? Attribute . IsDefined ( parameters [ parameters . Length - 1 ] , typeof ( ParamArrayAttribute ) ) : false ;
547
586
548
587
if ( positionalArgumentCount == parameters . Length )
549
588
{
@@ -572,7 +611,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
572
611
// to be passed in as the parameter value
573
612
defaultArgList . Add ( parameters [ v ] . GetDefaultValue ( ) ) ;
574
613
}
575
- else
614
+ else if ( ! paramsArray )
576
615
{
577
616
match = false ;
578
617
}
0 commit comments