Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Make indexers work for interface objects#1246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
lostmsu merged 2 commits intopythonnet:masterfromdanabr:interface-indexers
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletionsCHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@ details about the cause of the failure
- Fixed a bug where all .NET class instances were considered Iterable
- Fix incorrect choice of method to invoke when using keyword arguments.
- Fix non-delegate types incorrectly appearing as callable.
- Indexers can now be used with interface objects

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

Expand Down
4 changes: 2 additions & 2 deletionssrc/runtime/arrayobject.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
/// <summary>
/// Implements __getitem__ for array types.
/// </summary>
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
publicnewstatic IntPtr mp_subscript(IntPtr ob, IntPtr idx)
{
var obj = (CLRObject)GetManagedObject(ob);
var arrObj = (ArrayObject)GetManagedObjectType(ob);
Expand DownExpand Up@@ -133,7 +133,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
/// <summary>
/// Implements __setitem__ for array types.
/// </summary>
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
public staticnewint mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
{
var obj = (CLRObject)GetManagedObject(ob);
var items = obj.inst as Array;
Expand Down
124 changes: 124 additions & 0 deletionssrc/runtime/classbase.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -302,5 +302,129 @@ public static void tp_dealloc(IntPtr ob)
Runtime.XDecref(self.tpHandle);
self.gcHandle.Free();
}


/// <summary>
/// Implements __getitem__ for reflected classes and value types.
/// </summary>
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanGet)
{
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
return IntPtr.Zero;
}

// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
IntPtr args = idx;
var free = false;

if (!Runtime.PyTuple_Check(idx))
{
args = Runtime.PyTuple_New(1);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
free = true;
}

IntPtr value;

try
{
value = cls.indexer.GetItem(ob, args);
}
finally
{
if (free)
{
Runtime.XDecref(args);
}
}
return value;
}


/// <summary>
/// Implements __setitem__ for reflected classes and value types.
/// </summary>
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanSet)
{
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
return -1;
}

// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
IntPtr args = idx;
var free = false;

if (!Runtime.PyTuple_Check(idx))
{
args = Runtime.PyTuple_New(1);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
free = true;
}

// Get the args passed in.
var i = Runtime.PyTuple_Size(args);
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
var temp = i + numOfDefaultArgs;
IntPtr real = Runtime.PyTuple_New(temp + 1);
for (var n = 0; n < i; n++)
{
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Runtime.XIncref(item);
Runtime.PyTuple_SetItem(real, n, item);
}

// Add Default Args if needed
for (var n = 0; n < numOfDefaultArgs; n++)
{
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
Runtime.XIncref(item);
Runtime.PyTuple_SetItem(real, n + i, item);
}
// no longer need defaultArgs
Runtime.XDecref(defaultArgs);
i = temp;

// Add value to argument list
Runtime.XIncref(v);
Runtime.PyTuple_SetItem(real, i, v);

try
{
cls.indexer.SetItem(ob, real);
}
finally
{
Runtime.XDecref(real);

if (free)
{
Runtime.XDecref(args);
}
}

if (Exceptions.ErrorOccurred())
{
return -1;
}

return 0;
}
}
}
126 changes: 0 additions & 126 deletionssrc/runtime/classobject.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -152,131 +152,5 @@ public override IntPtr type_subscript(IntPtr idx)
}
return Exceptions.RaiseTypeError("unsubscriptable object");
}


/// <summary>
/// Implements __getitem__ for reflected classes and value types.
/// </summary>
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
{
//ManagedType self = GetManagedObject(ob);
IntPtr tp = Runtime.PyObject_TYPE(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanGet)
{
Exceptions.SetError(Exceptions.TypeError, "unindexable object");
return IntPtr.Zero;
}

// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
IntPtr args = idx;
var free = false;

if (!Runtime.PyTuple_Check(idx))
{
args = Runtime.PyTuple_New(1);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
free = true;
}

IntPtr value;

try
{
value = cls.indexer.GetItem(ob, args);
}
finally
{
if (free)
{
Runtime.XDecref(args);
}
}
return value;
}


/// <summary>
/// Implements __setitem__ for reflected classes and value types.
/// </summary>
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
{
//ManagedType self = GetManagedObject(ob);
IntPtr tp = Runtime.PyObject_TYPE(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanSet)
{
Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment");
return -1;
}

// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
IntPtr args = idx;
var free = false;

if (!Runtime.PyTuple_Check(idx))
{
args = Runtime.PyTuple_New(1);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
free = true;
}

// Get the args passed in.
var i = Runtime.PyTuple_Size(args);
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
var temp = i + numOfDefaultArgs;
IntPtr real = Runtime.PyTuple_New(temp + 1);
for (var n = 0; n < i; n++)
{
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Runtime.XIncref(item);
Runtime.PyTuple_SetItem(real, n, item);
}

// Add Default Args if needed
for (var n = 0; n < numOfDefaultArgs; n++)
{
IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
Runtime.XIncref(item);
Runtime.PyTuple_SetItem(real, n + i, item);
}
// no longer need defaultArgs
Runtime.XDecref(defaultArgs);
i = temp;

// Add value to argument list
Runtime.XIncref(v);
Runtime.PyTuple_SetItem(real, i, v);

try
{
cls.indexer.SetItem(ob, real);
}
finally
{
Runtime.XDecref(real);

if (free)
{
Runtime.XDecref(args);
}
}

if (Exceptions.ErrorOccurred())
{
return -1;
}

return 0;
}
}
}
22 changes: 22 additions & 0 deletionssrc/runtime/typemanager.cs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -171,6 +171,28 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
}


// Only set mp_subscript and mp_ass_subscript for types with indexers
if (impl is ClassBase cb)
{
if (!(impl is ArrayObject))
{
if (cb.indexer == null || !cb.indexer.CanGet)
{
Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
}
if (cb.indexer == null || !cb.indexer.CanSet)
{
Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
}
}
}
else
{
Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
}

if (base_ != IntPtr.Zero)
{
Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
Expand Down
12 changes: 5 additions & 7 deletionssrc/tests/test_array.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1321,16 +1321,14 @@ def test_array_abuse():
with pytest.raises(TypeError):
Test.PublicArrayTest.__getitem__(0, 0)

with pytest.raises(TypeError):
with pytest.raises(AttributeError):
Test.PublicArrayTest.__setitem__(0, 0, 0)

with pytest.raises(TypeError):
desc = Test.PublicArrayTest.__dict__['__getitem__']
desc(0, 0)
with pytest.raises(KeyError):
Test.PublicArrayTest.__dict__['__getitem__']

with pytest.raises(TypeError):
desc = Test.PublicArrayTest.__dict__['__setitem__']
desc(0, 0, 0)
with pytest.raises(KeyError):
Test.PublicArrayTest.__dict__['__setitem__']


def test_iterator_to_array():
Expand Down
23 changes: 21 additions & 2 deletionssrc/tests/test_indexer.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ def test_internal_indexer():
with pytest.raises(TypeError):
Test.InternalIndexerTest.__getitem__(ob, 0)

with pytest.raises(TypeError):
with pytest.raises(AttributeError):
ob.__getitem__(0)


Expand All@@ -56,7 +56,7 @@ def test_private_indexer():
with pytest.raises(TypeError):
Test.PrivateIndexerTest.__getitem__(ob, 0)

with pytest.raises(TypeError):
with pytest.raises(AttributeError):
ob.__getitem__(0)


Expand DownExpand Up@@ -595,3 +595,22 @@ def test_indexer_abuse():

with pytest.raises(AttributeError):
del ob.__setitem__


def test_indexer_accessed_through_interface():
"""Test that indexers can be accessed through interfaces"""
from System.Collections.Generic import Dictionary, IDictionary
d = IDictionary[str, str](Dictionary[str, str]())
d["one"] = "1"
assert d["one"] == "1"


def test_using_indexer_on_object_without_indexer():
"""Test using subscript syntax on an object an without indexer raises"""
from System import Object
o = Object()
with pytest.raises(TypeError):
o[0]

with pytest.raises(TypeError):
o[0] = 1

[8]ページ先頭

©2009-2025 Movatter.jp