Merge pull request #1786 from losttech/bugs/KeyCollection

Multiple fixes related to Dictionary.Keys bug
This commit is contained in:
Victor 2022-05-19 17:15:26 -07:00 коммит произвёл GitHub
Родитель a80c685d19 d8543321a3
Коммит 87d4db92f6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 91 добавлений и 7 удалений

Просмотреть файл

@ -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