Skip to content

Commit b5ba815

Browse files
authored
Ensure only implementers of IEnumerable or IEnumerator are considered Iterable (#1241)
Fixes #1234. Previously `tp_iter` slot was set for all reflected .NET types. This restricts it to types, that implement `IEnumerable` or `IEnumerator`
1 parent 451fae6 commit b5ba815

File tree

4 files changed

+26
-0
lines changed

4 files changed

+26
-0
lines changed

AUTHORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- Christoph Gohlke ([@cgohlke](https://github.com/cgohlke))
2929
- Christopher Bremner ([@chrisjbremner](https://github.com/chrisjbremner))
3030
- Christopher Pow ([@christopherpow](https://github.com/christopherpow))
31+
- Daniel Abrahamsson ([@danabr](https://github.com/danabr))
3132
- Daniel Fernandez ([@fdanny](https://github.com/fdanny))
3233
- Daniel Santana ([@dgsantana](https://github.com/dgsantana))
3334
- Dave Hirschfeld ([@dhirschfeld](https://github.com/dhirschfeld))

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ details about the cause of the failure
2121
- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash
2222
- Fix incorrect dereference in params array handling
2323
- Fix `object[]` parameters taking precedence when should not in overload resolution
24+
- Fixed a bug where all .NET class instances were considered Iterable
2425

2526
## [2.5.0][] - 2020-06-14
2627

src/runtime/typemanager.cs

+7
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
164164
// we want to do this after the slot stuff above in case the class itself implements a slot method
165165
InitializeSlots(type, impl.GetType());
166166

167+
if (!clrType.GetInterfaces().Any(ifc => ifc == typeof(IEnumerable) || ifc == typeof(IEnumerator)))
168+
{
169+
// The tp_iter slot should only be set for enumerable types.
170+
Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
171+
}
172+
173+
167174
if (base_ != IntPtr.Zero)
168175
{
169176
Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);

src/tests/test_class.py

+17
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,23 @@ def test_ienumerator_iteration():
172172
for item in chars:
173173
assert item in 'test string'
174174

175+
def test_iterable():
176+
"""Test what objects are Iterable"""
177+
from collections.abc import Iterable
178+
from Python.Test import ClassTest
179+
180+
assert isinstance(System.String.Empty, Iterable)
181+
assert isinstance(ClassTest.GetArrayList(), Iterable)
182+
assert isinstance(ClassTest.GetEnumerator(), Iterable)
183+
assert (not isinstance(ClassTest, Iterable))
184+
assert (not isinstance(ClassTest(), Iterable))
185+
186+
class ShouldBeIterable(ClassTest):
187+
def __iter__(self):
188+
return iter([])
189+
190+
assert isinstance(ShouldBeIterable(), Iterable)
191+
175192

176193
def test_override_get_item():
177194
"""Test managed subclass overriding __getitem__."""

0 commit comments

Comments
 (0)