@@ -837,48 +837,98 @@ private static void SetConversionError(IntPtr value, Type target)
837
837
838
838
/// <summary>
839
839
/// Convert a Python value to a correctly typed managed array instance.
840
- /// The Python value must support the Python sequence protocol and the
841
- /// items in the sequence must be convertible to the target array type.
840
+ /// The Python value must support either the Python sequence protocol or
841
+ /// the Python iterator protocol and the items in the sequence must be
842
+ /// convertible to the target array type.
842
843
/// </summary>
843
844
private static bool ToArray ( IntPtr value , Type obType , out object result , bool setError )
844
845
{
845
846
Type elementType = obType . GetElementType ( ) ;
846
- var size = Runtime . PySequence_Size ( value ) ;
847
847
result = null ;
848
848
849
- if ( size < 0 )
849
+ bool IsSeqObj = Runtime . PySequence_Check ( value ) ;
850
+
851
+ // If object does not support Sequence Protocol check if it supports iterator protocol
852
+ IntPtr IterObject = IntPtr . Zero ;
853
+ if ( ! IsSeqObj )
850
854
{
855
+ IterObject = Runtime . PyObject_GetIter ( value ) ;
856
+ }
857
+
858
+ if ( ! IsSeqObj && IterObject == IntPtr . Zero ) {
859
+ // Bail if both sequence check and iterator conversion attempt fail
851
860
if ( setError )
852
861
{
853
862
SetConversionError ( value , obType ) ;
854
863
}
855
864
return false ;
856
865
}
857
866
858
- Array items = Array . CreateInstance ( elementType , size ) ;
867
+ Array items ;
859
868
860
869
// XXX - is there a better way to unwrap this if it is a real array?
861
- for ( var i = 0 ; i < size ; i ++ )
870
+ if ( IsSeqObj )
862
871
{
863
- object obj = null ;
864
- IntPtr item = Runtime . PySequence_GetItem ( value , i ) ;
865
- if ( item == IntPtr . Zero )
872
+ // If we have a sequence object use the sequence protocol
873
+ var size = Runtime . PySequence_Size ( value ) ;
874
+ if ( size < 0 )
866
875
{
867
876
if ( setError )
868
877
{
869
878
SetConversionError ( value , obType ) ;
879
+ }
880
+ return false ;
881
+ }
882
+
883
+ items = Array . CreateInstance ( elementType , size ) ;
884
+ for ( var i = 0 ; i < size ; i ++ )
885
+ {
886
+ object obj = null ;
887
+ IntPtr item = Runtime . PySequence_GetItem ( value , i ) ;
888
+ if ( item == IntPtr . Zero )
889
+ {
890
+ if ( setError )
891
+ {
892
+ SetConversionError ( value , obType ) ;
893
+ }
870
894
return false ;
871
895
}
896
+
897
+ if ( ! Converter . ToManaged ( item , elementType , out obj , true ) )
898
+ {
899
+ Runtime . XDecref ( item ) ;
900
+ return false ;
901
+ }
902
+
903
+ items . SetValue ( obj , i ) ;
904
+ Runtime . XDecref ( item ) ;
872
905
}
906
+ }
907
+ else
908
+ {
909
+ // Otherwise use iterator protocol
910
+ var listType = typeof ( List < > ) ;
911
+ var constructedListType = listType . MakeGenericType ( elementType ) ;
912
+ IList list = ( IList ) Activator . CreateInstance ( constructedListType ) ;
913
+ IntPtr item ;
873
914
874
- if ( ! Converter . ToManaged ( item , elementType , out obj , true ) )
915
+ while ( ( item = Runtime . PyIter_Next ( IterObject ) ) != IntPtr . Zero )
875
916
{
917
+ object obj = null ;
918
+
919
+ if ( ! Converter . ToManaged ( item , elementType , out obj , true ) )
920
+ {
921
+ Runtime . XDecref ( item ) ;
922
+ return false ;
923
+ }
924
+
925
+ list . Add ( obj ) ;
876
926
Runtime . XDecref ( item ) ;
877
- return false ;
878
927
}
928
+ Runtime . XDecref ( IterObject ) ;
879
929
880
- items . SetValue ( obj , i ) ;
881
- Runtime . XDecref ( item ) ;
930
+ items = Array . CreateInstance ( elementType , list . Count ) ;
931
+ list . CopyTo ( items , 0 ) ;
882
932
}
883
933
884
934
result = items ;
0 commit comments