Merge pull request #1786 from losttech/bugs/KeyCollection
Multiple fixes related to Dictionary.Keys bug
This commit is contained in:
Коммит
87d4db92f6
|
@ -21,6 +21,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
|
||||||
- `__name__` and `__signature__` to reflected .NET methods
|
- `__name__` and `__signature__` to reflected .NET methods
|
||||||
- .NET collection types now implement standard Python collection interfaces from `collections.abc`.
|
- .NET collection types now implement standard Python collection interfaces from `collections.abc`.
|
||||||
See [Mixins/collections.py](src/runtime/Mixins/collections.py).
|
See [Mixins/collections.py](src/runtime/Mixins/collections.py).
|
||||||
|
- you can cast objects to generic .NET interfaces without specifying generic arguments as long as there is no ambiguity.
|
||||||
- .NET arrays implement Python buffer protocol
|
- .NET arrays implement Python buffer protocol
|
||||||
- Python integer interoperability with `System.Numerics.BigInteger`
|
- Python integer interoperability with `System.Numerics.BigInteger`
|
||||||
- Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`,
|
- Python.NET will correctly resolve .NET methods, that accept `PyList`, `PyInt`,
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace Python.Runtime
|
||||||
/// Return the ClassBase-derived instance that implements a particular
|
/// Return the ClassBase-derived instance that implements a particular
|
||||||
/// reflected managed type, creating it if it doesn't yet exist.
|
/// reflected managed type, creating it if it doesn't yet exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ReflectedClrType GetClass(Type type) => ReflectedClrType.GetOrCreate(type);
|
internal static BorrowedReference GetClass(Type type) => ReflectedClrType.GetOrCreate(type);
|
||||||
|
|
||||||
internal static ClassBase GetClassImpl(Type type)
|
internal static ClassBase GetClassImpl(Type type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,11 @@ import collections.abc as col
|
||||||
|
|
||||||
class IteratorMixin(col.Iterator):
|
class IteratorMixin(col.Iterator):
|
||||||
def close(self):
|
def close(self):
|
||||||
self.Dispose()
|
if hasattr(self, 'Dispose'):
|
||||||
|
self.Dispose()
|
||||||
|
else:
|
||||||
|
from System import IDisposable
|
||||||
|
IDisposable(self).Dispose()
|
||||||
|
|
||||||
class IterableMixin(col.Iterable):
|
class IterableMixin(col.Iterable):
|
||||||
pass
|
pass
|
||||||
|
@ -16,7 +20,12 @@ class SizedMixin(col.Sized):
|
||||||
def __len__(self): return self.Count
|
def __len__(self): return self.Count
|
||||||
|
|
||||||
class ContainerMixin(col.Container):
|
class ContainerMixin(col.Container):
|
||||||
def __contains__(self, item): return self.Contains(item)
|
def __contains__(self, item):
|
||||||
|
if hasattr('self', 'Contains'):
|
||||||
|
return self.Contains(item)
|
||||||
|
else:
|
||||||
|
from System.Collections.Generic import ICollection
|
||||||
|
return ICollection(self).Contains(item)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
abc_Collection = col.Collection
|
abc_Collection = col.Collection
|
||||||
|
|
|
@ -217,6 +217,23 @@ namespace Python.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
target.Append(']');
|
target.Append(']');
|
||||||
|
|
||||||
|
int nestedStart = fullName.IndexOf('+');
|
||||||
|
while (nestedStart >= 0)
|
||||||
|
{
|
||||||
|
target.Append('.');
|
||||||
|
int nextNested = fullName.IndexOf('+', nestedStart + 1);
|
||||||
|
if (nextNested < 0)
|
||||||
|
{
|
||||||
|
target.Append(fullName.Substring(nestedStart + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.Append(fullName.Substring(nestedStart + 1, length: nextNested - nestedStart - 1));
|
||||||
|
}
|
||||||
|
nestedStart = nextNested;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,7 @@ namespace Python.Runtime
|
||||||
return Exceptions.RaiseTypeError("type expected");
|
return Exceptions.RaiseTypeError("type expected");
|
||||||
}
|
}
|
||||||
Type a = t.MakeArrayType();
|
Type a = t.MakeArrayType();
|
||||||
PyType o = ClassManager.GetClass(a);
|
BorrowedReference o = ClassManager.GetClass(a);
|
||||||
return new NewReference(o);
|
return new NewReference(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,13 @@ namespace Python.Runtime
|
||||||
|
|
||||||
internal static NewReference GetReference(object ob, Type type)
|
internal static NewReference GetReference(object ob, Type type)
|
||||||
{
|
{
|
||||||
PyType cc = ClassManager.GetClass(type);
|
BorrowedReference cc = ClassManager.GetClass(type);
|
||||||
return Create(ob, cc);
|
return Create(ob, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static NewReference GetReference(object ob)
|
internal static NewReference GetReference(object ob)
|
||||||
{
|
{
|
||||||
PyType cc = ClassManager.GetClass(ob.GetType());
|
BorrowedReference cc = ClassManager.GetClass(ob.GetType());
|
||||||
return Create(ob, cc);
|
return Create(ob, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Python.Runtime
|
namespace Python.Runtime
|
||||||
{
|
{
|
||||||
|
@ -20,10 +21,58 @@ namespace Python.Runtime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw)
|
public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw)
|
||||||
{
|
{
|
||||||
|
var self = (GenericType)GetManagedObject(tp)!;
|
||||||
|
if (!self.type.Valid)
|
||||||
|
{
|
||||||
|
return Exceptions.RaiseTypeError(self.type.DeletedMessage);
|
||||||
|
}
|
||||||
|
var type = self.type.Value;
|
||||||
|
|
||||||
|
if (type.IsInterface && !type.IsConstructedGenericType)
|
||||||
|
{
|
||||||
|
var nargs = Runtime.PyTuple_Size(args);
|
||||||
|
if (nargs == 1)
|
||||||
|
{
|
||||||
|
var instance = Runtime.PyTuple_GetItem(args, 0);
|
||||||
|
return AsGenericInterface(instance, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Exceptions.SetError(Exceptions.TypeError, "cannot instantiate an open generic type");
|
Exceptions.SetError(Exceptions.TypeError, "cannot instantiate an open generic type");
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NewReference AsGenericInterface(BorrowedReference instance, Type targetType)
|
||||||
|
{
|
||||||
|
if (GetManagedObject(instance) is not CLRObject obj)
|
||||||
|
{
|
||||||
|
return Exceptions.RaiseTypeError("only .NET objects can be cast to .NET interfaces");
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] supportedInterfaces = obj.inst.GetType().GetInterfaces();
|
||||||
|
Type[] constructedInterfaces = supportedInterfaces
|
||||||
|
.Where(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == targetType)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (constructedInterfaces.Length == 1)
|
||||||
|
{
|
||||||
|
BorrowedReference pythonic = ClassManager.GetClass(constructedInterfaces[0]);
|
||||||
|
using var args = Runtime.PyTuple_New(1);
|
||||||
|
Runtime.PyTuple_SetItem(args.Borrow(), 0, instance);
|
||||||
|
return Runtime.PyObject_CallObject(pythonic, args.Borrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constructedInterfaces.Length > 1)
|
||||||
|
{
|
||||||
|
string interfaces = string.Join(", ", constructedInterfaces.Select(TypeManager.GetPythonTypeName));
|
||||||
|
return Exceptions.RaiseTypeError("Ambiguous cast to .NET interface. "
|
||||||
|
+ $"Object implements: {interfaces}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Exceptions.RaiseTypeError("object does not implement "
|
||||||
|
+ TypeManager.GetPythonTypeName(targetType));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements __call__ for reflected generic types.
|
/// Implements __call__ for reflected generic types.
|
||||||
|
|
|
@ -191,7 +191,7 @@ namespace Python.Runtime
|
||||||
&& obj.inst is IPythonDerivedType
|
&& obj.inst is IPythonDerivedType
|
||||||
&& self.type.Value.IsInstanceOfType(obj.inst))
|
&& self.type.Value.IsInstanceOfType(obj.inst))
|
||||||
{
|
{
|
||||||
var basecls = ClassManager.GetClass(self.type.Value);
|
var basecls = ReflectedClrType.GetOrCreate(self.type.Value);
|
||||||
return new MethodBinding(self, new PyObject(ob), basecls).Alloc();
|
return new MethodBinding(self, new PyObject(ob), basecls).Alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ internal sealed class ReflectedClrType : PyType
|
||||||
{
|
{
|
||||||
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
|
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
|
||||||
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
|
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
|
||||||
|
internal ReflectedClrType(BorrowedReference original) : base(original) { }
|
||||||
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
|
|
||||||
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
|
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
|
||||||
|
|
|
@ -14,3 +14,10 @@ def test_dict_items():
|
||||||
k,v = items[0]
|
k,v = items[0]
|
||||||
assert k == 42
|
assert k == 42
|
||||||
assert v == "a"
|
assert v == "a"
|
||||||
|
|
||||||
|
# regression test for https://github.com/pythonnet/pythonnet/issues/1785
|
||||||
|
def test_dict_in_keys():
|
||||||
|
d = C.Dictionary[str, int]()
|
||||||
|
d["a"] = 42
|
||||||
|
assert "a" in d.Keys
|
||||||
|
assert "b" not in d.Keys
|
||||||
|
|
Загрузка…
Ссылка в новой задаче