Skip to content

Commit c79be84

Browse files
danabrlostmsu
authored andcommitted
Make it possible to use inherited indexers
If a class A had indexer, and class B derived from it, Python.NET would not consider class B to have any indexer.
1 parent f808166 commit c79be84

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ details about the cause of the failure
3030
- Fix incorrect choice of method to invoke when using keyword arguments.
3131
- Fix non-delegate types incorrectly appearing as callable.
3232
- Indexers can now be used with interface objects
33+
- Fixed a bug where indexers could not be used if they were inherited
3334

3435
## [2.5.0][] - 2020-06-14
3536

src/runtime/classmanager.cs

+19
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,25 @@ private static ClassInfo GetClassInfo(Type type)
389389
ci.members[name] = ob;
390390
}
391391

392+
if (ci.indexer == null && type.IsClass)
393+
{
394+
// Indexer may be inherited.
395+
var parent = type.BaseType;
396+
while (parent != null && ci.indexer == null)
397+
{
398+
foreach (var prop in parent.GetProperties()) {
399+
var args = prop.GetIndexParameters();
400+
if (args.GetLength(0) > 0)
401+
{
402+
ci.indexer = new Indexer();
403+
ci.indexer.AddProperty(prop);
404+
break;
405+
}
406+
}
407+
parent = parent.BaseType;
408+
}
409+
}
410+
392411
return ci;
393412
}
394413
}

src/testing/indexertest.cs

+25
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,29 @@ public MultiDefaultKeyIndexerTest() : base()
411411
}
412412
}
413413
}
414+
415+
public class PublicInheritedIndexerTest : PublicIndexerTest { }
416+
417+
public class ProtectedInheritedIndexerTest : ProtectedIndexerTest { }
418+
419+
public class PrivateInheritedIndexerTest : ProtectedIndexerTest { }
420+
421+
public class InternalInheritedIndexerTest : InternalIndexerTest { }
422+
423+
public interface IIndexer
424+
{
425+
string this[int index] { get; set; }
426+
}
427+
428+
public interface IInheritedIndexer : IIndexer { }
429+
430+
public class InterfaceInheritedIndexerTest :IndexerBase, IInheritedIndexer {
431+
private System.Collections.Generic.IDictionary<int, string> d = new System.Collections.Generic.Dictionary<int, string>();
432+
433+
public string this[int index]
434+
{
435+
get { return GetValue(index); }
436+
set { t[index] = value; }
437+
}
438+
}
414439
}

src/tests/test_indexer.py

+32
Original file line numberDiff line numberDiff line change
@@ -614,3 +614,35 @@ def test_using_indexer_on_object_without_indexer():
614614

615615
with pytest.raises(TypeError):
616616
o[0] = 1
617+
618+
619+
def test_inherited_indexer():
620+
"""Test that inherited indexers are accessible"""
621+
from Python.Test import PublicInheritedIndexerTest
622+
from Python.Test import ProtectedInheritedIndexerTest
623+
from Python.Test import PrivateInheritedIndexerTest
624+
from Python.Test import InternalInheritedIndexerTest
625+
626+
pub = PublicInheritedIndexerTest()
627+
pub[0] = "zero"
628+
assert pub[0] == "zero"
629+
630+
def assert_no_indexer(obj):
631+
with pytest.raises(TypeError):
632+
obj[0]
633+
with pytest.raises(TypeError):
634+
obj[0] = "zero"
635+
636+
assert_no_indexer(PrivateInheritedIndexerTest)
637+
assert_no_indexer(ProtectedInheritedIndexerTest)
638+
assert_no_indexer(InternalInheritedIndexerTest)
639+
640+
641+
def test_inherited_indexer_interface():
642+
"""Test that indexers inherited from other interfaces are accessible"""
643+
from Python.Test import InterfaceInheritedIndexerTest, IInheritedIndexer
644+
645+
impl = InterfaceInheritedIndexerTest()
646+
ifc = IInheritedIndexer(impl)
647+
ifc[0] = "zero"
648+
assert ifc[0] == "zero"

0 commit comments

Comments
 (0)