Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3eb7e58

Browse files
authored
Merge pull request #693 from ArvidJB/issue-475
Catching exceptions from iterator MoveNext(), additional testing (issue #475, original pull request #523)
2 parents 545c549 + 2131292 commit 3eb7e58

File tree

4 files changed

+66
-3
lines changed

4 files changed

+66
-3
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1616
- Added `clr.GetClrType` (#432, #433)
1717
- Allowed passing `None` for nullable args (#460)
1818
- Added keyword arguments based on C# syntax for calling CPython methods (#461)
19+
- Catches exceptions thrown in C# iterators (yield returns) and rethrows them in python (#475)
1920
- Implemented GetDynamicMemberNames() for PyObject to allow dynamic object members to be visible in the debugger (#443)
2021

2122
### Changed
@@ -29,7 +30,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
2930
- Fixed conversion of 'float' and 'double' values (#486)
3031
- Fixed 'clrmethod' for python 2 (#492)
3132
- Fixed double calling of constructor when deriving from .NET class (#495)
32-
- Fixed `clr.GetClrType` when iterating over `System` members (#607)
33+
- Fixed `clr.GetClrType` when iterating over `System` members (#607)
3334
- Fixed `LockRecursionException` when loading assemblies (#627)
3435
- Fixed errors breaking .NET Remoting on method invoke (#276)
3536
- Fixed PyObject.GetHashCode (#676)

src/runtime/iterator.cs

+14-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,21 @@ public Iterator(IEnumerator e)
2323
public static IntPtr tp_iternext(IntPtr ob)
2424
{
2525
var self = GetManagedObject(ob) as Iterator;
26-
if (!self.iter.MoveNext())
26+
try
2727
{
28-
Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone);
28+
if (!self.iter.MoveNext())
29+
{
30+
Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone);
31+
return IntPtr.Zero;
32+
}
33+
}
34+
catch (Exception e)
35+
{
36+
if (e.InnerException != null)
37+
{
38+
e = e.InnerException;
39+
}
40+
Exceptions.SetError(e);
2941
return IntPtr.Zero;
3042
}
3143
object item = self.iter.Current;

src/testing/exceptiontest.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
24

35
namespace Python.Test
46
{
@@ -54,6 +56,13 @@ public static bool ThrowException()
5456
throw new OverflowException("error");
5557
}
5658

59+
public static IEnumerable<int> ThrowExceptionInIterator(Exception e)
60+
{
61+
yield return 1;
62+
yield return 2;
63+
throw e;
64+
}
65+
5766
public static void ThrowChainedExceptions()
5867
{
5968
try

src/tests/test_exceptions.py

+41
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,44 @@ def test_chained_exceptions():
345345
assert exc.Message == msg
346346
assert exc.__cause__ == exc.InnerException
347347
exc = exc.__cause__
348+
349+
def test_iteration_exception():
350+
from Python.Test import ExceptionTest
351+
from System import OverflowException
352+
353+
exception = OverflowException("error")
354+
355+
val = ExceptionTest.ThrowExceptionInIterator(exception).__iter__()
356+
assert next(val) == 1
357+
assert next(val) == 2
358+
with pytest.raises(OverflowException) as cm:
359+
next(val)
360+
361+
exc = cm.value
362+
363+
assert exc == exception
364+
365+
# after exception is thrown iterator is no longer valid
366+
with pytest.raises(StopIteration):
367+
next(val)
368+
369+
370+
def test_iteration_innerexception():
371+
from Python.Test import ExceptionTest
372+
from System import OverflowException
373+
374+
exception = System.Exception("message", OverflowException("error"))
375+
376+
val = ExceptionTest.ThrowExceptionInIterator(exception).__iter__()
377+
assert next(val) == 1
378+
assert next(val) == 2
379+
with pytest.raises(OverflowException) as cm:
380+
next(val)
381+
382+
exc = cm.value
383+
384+
assert exc == exception.InnerException
385+
386+
# after exception is thrown iterator is no longer valid
387+
with pytest.raises(StopIteration):
388+
next(val)

0 commit comments

Comments
 (0)