File tree Expand file tree Collapse file tree 5 files changed +58
-22
lines changed
Expand file tree Collapse file tree 5 files changed +58
-22
lines changed Original file line number Diff line number Diff line change @@ -26,6 +26,7 @@ details about the cause of the failure
2626- BREAKING: Parameters marked with ` ParameterAttributes.Out ` are no longer returned in addition
2727 to the regular method return value (unless they are passed with ` ref ` or ` out ` keyword).
2828- BREAKING: Drop support for the long-deprecated CLR.* prefix.
29+ - ` PyObject ` now implements ` IEnumerable<PyObject> ` in addition to ` IEnumerable `
2930
3031### Fixed
3132
@@ -40,6 +41,7 @@ details about the cause of the failure
4041- Fixed a bug where indexers could not be used if they were inherited
4142- Made it possible to use ` __len__ ` also on ` ICollection<> ` interface objects
4243- Made it possible to call ` ToString ` , ` GetHashCode ` , and ` GetType ` on inteface objects
44+ - Fixed objects returned by enumerating ` PyObject ` being disposed too soon
4345
4446### Removed
4547
Original file line number Diff line number Diff line change 1+ using System . Linq ;
2+ using System . Text ;
3+
4+ using NUnit . Framework ;
5+
6+ using Python . Runtime ;
7+
8+ namespace Python . EmbeddingTest
9+ {
10+ class TestPyIter
11+ {
12+ [ OneTimeSetUp ]
13+ public void SetUp ( )
14+ {
15+ PythonEngine . Initialize ( ) ;
16+ }
17+
18+ [ OneTimeTearDown ]
19+ public void Dispose ( )
20+ {
21+ PythonEngine . Shutdown ( ) ;
22+ }
23+
24+ [ Test ]
25+ public void KeepOldObjects ( )
26+ {
27+ using ( Py . GIL ( ) )
28+ using ( var testString = new PyString ( "hello world! !$%&/()=?" ) )
29+ {
30+ PyObject [ ] chars = testString . ToArray ( ) ;
31+ Assert . IsTrue ( chars . Length > 1 ) ;
32+ string reconstructed = string . Concat ( chars . Select ( c => c . As < string > ( ) ) ) ;
33+ Assert . AreEqual ( testString . As < string > ( ) , reconstructed ) ;
34+ }
35+ }
36+ }
37+ }
Original file line number Diff line number Diff line change @@ -9,7 +9,7 @@ namespace Python.Runtime
99 /// PY3: https://docs.python.org/3/c-api/iterator.html
1010 /// for details.
1111 /// </summary>
12- public class PyIter : PyObject , IEnumerator < object >
12+ public class PyIter : PyObject , IEnumerator < PyObject >
1313 {
1414 private PyObject _current ;
1515
@@ -46,41 +46,35 @@ public static PyIter GetIter(PyObject iterable)
4646
4747 protected override void Dispose ( bool disposing )
4848 {
49- if ( null != _current )
50- {
51- _current . Dispose ( ) ;
52- _current = null ;
53- }
49+ _current = null ;
5450 base . Dispose ( disposing ) ;
5551 }
5652
5753 public bool MoveNext ( )
5854 {
59- // dispose of the previous object, if there was one
60- if ( null != _current )
55+ NewReference next = Runtime . PyIter_Next ( Reference ) ;
56+ if ( next . IsNull ( ) )
6157 {
62- _current . Dispose ( ) ;
63- _current = null ;
64- }
58+ if ( Exceptions . ErrorOccurred ( ) )
59+ {
60+ throw new PythonException ( ) ;
61+ }
6562
66- IntPtr next = Runtime . PyIter_Next ( obj ) ;
67- if ( next == IntPtr . Zero )
68- {
63+ // stop holding the previous object, if there was one
64+ _current = null ;
6965 return false ;
7066 }
7167
72- _current = new PyObject ( next ) ;
68+ _current = next . MoveToPyObject ( ) ;
7369 return true ;
7470 }
7571
7672 public void Reset ( )
7773 {
78- //Not supported in python.
74+ throw new NotSupportedException ( ) ;
7975 }
8076
81- public object Current
82- {
83- get { return _current ; }
84- }
77+ public PyObject Current => _current ;
78+ object System . Collections . IEnumerator . Current => _current ;
8579 }
8680}
Original file line number Diff line number Diff line change @@ -16,7 +16,7 @@ namespace Python.Runtime
1616 /// for details.
1717 /// </summary>
1818 [ Serializable ]
19- public partial class PyObject : DynamicObject , IEnumerable , IDisposable
19+ public partial class PyObject : DynamicObject , IEnumerable < PyObject > , IDisposable
2020 {
2121#if TRACE_ALLOC
2222 /// <summary>
@@ -705,10 +705,11 @@ public PyObject GetIterator()
705705 /// python object to be iterated over in C#. A PythonException will be
706706 /// raised if the object is not iterable.
707707 /// </remarks>
708- public IEnumerator GetEnumerator ( )
708+ public IEnumerator < PyObject > GetEnumerator ( )
709709 {
710710 return PyIter . GetIter ( this ) ;
711711 }
712+ IEnumerator IEnumerable . GetEnumerator ( ) => this . GetEnumerator ( ) ;
712713
713714
714715 /// <summary>
Original file line number Diff line number Diff line change @@ -1854,6 +1854,8 @@ internal static bool PyIter_Check(IntPtr pointer)
18541854
18551855 [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
18561856 internal static extern IntPtr PyIter_Next( IntPtr pointer) ;
1857+ [ DllImport( _PythonDll, CallingConvention = CallingConvention. Cdecl) ]
1858+ internal static extern NewReference PyIter_Next( BorrowedReference pointer) ;
18571859
18581860
18591861 //====================================================================
You can’t perform that action at this time.
0 commit comments