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
|
||||
- .NET collection types now implement standard Python collection interfaces from `collections.abc`.
|
||||
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
|
||||
- Python integer interoperability with `System.Numerics.BigInteger`
|
||||
- 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
|
||||
/// reflected managed type, creating it if it doesn't yet exist.
|
||||
/// </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)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,11 @@ import collections.abc as col
|
|||
|
||||
class IteratorMixin(col.Iterator):
|
||||
def close(self):
|
||||
if hasattr(self, 'Dispose'):
|
||||
self.Dispose()
|
||||
else:
|
||||
from System import IDisposable
|
||||
IDisposable(self).Dispose()
|
||||
|
||||
class IterableMixin(col.Iterable):
|
||||
pass
|
||||
|
@ -16,7 +20,12 @@ class SizedMixin(col.Sized):
|
|||
def __len__(self): return self.Count
|
||||
|
||||
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:
|
||||
abc_Collection = col.Collection
|
||||
|
|
|
@ -217,6 +217,23 @@ namespace Python.Runtime
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ namespace Python.Runtime
|
|||
return Exceptions.RaiseTypeError("type expected");
|
||||
}
|
||||
Type a = t.MakeArrayType();
|
||||
PyType o = ClassManager.GetClass(a);
|
||||
BorrowedReference o = ClassManager.GetClass(a);
|
||||
return new NewReference(o);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,13 +43,13 @@ namespace Python.Runtime
|
|||
|
||||
internal static NewReference GetReference(object ob, Type type)
|
||||
{
|
||||
PyType cc = ClassManager.GetClass(type);
|
||||
BorrowedReference cc = ClassManager.GetClass(type);
|
||||
return Create(ob, cc);
|
||||
}
|
||||
|
||||
internal static NewReference GetReference(object ob)
|
||||
{
|
||||
PyType cc = ClassManager.GetClass(ob.GetType());
|
||||
BorrowedReference cc = ClassManager.GetClass(ob.GetType());
|
||||
return Create(ob, cc);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Python.Runtime
|
||||
{
|
||||
|
@ -20,10 +21,58 @@ namespace Python.Runtime
|
|||
/// </summary>
|
||||
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");
|
||||
|
||||
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>
|
||||
/// Implements __call__ for reflected generic types.
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace Python.Runtime
|
|||
&& obj.inst is IPythonDerivedType
|
||||
&& 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ internal sealed class ReflectedClrType : PyType
|
|||
{
|
||||
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
|
||||
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
|
||||
internal ReflectedClrType(BorrowedReference original) : base(original) { }
|
||||
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
|
||||
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
|
||||
|
|
|
@ -14,3 +14,10 @@ def test_dict_items():
|
|||
k,v = items[0]
|
||||
assert k == 42
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче