Skip to content

Changed signature of IPyObjectDecoder.CanDecode #1583

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2021
Merged
Show file tree
Hide file tree
Changes from all 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 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Python `float` will continue to be converted to `System.Double`.
- BREAKING: `PyObject.GetAttr(name, default)` now only ignores `AttributeError` (previously ignored all exceptions).
- BREAKING: `PyObject` no longer implements `IEnumerable<PyObject>`.
Instead, `PyIterable` does that.
- BREAKING: `IPyObjectDecoder.CanDecode` `objectType` parameter type changed from `PyObject` to `PyType`

### Fixed

Expand Down
25 changes: 13 additions & 12 deletions src/embed_tests/Codecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,17 @@ public void SequenceDecoderTest()

//SequenceConverter can only convert to any ICollection
var pyList = new PyList(items.ToArray());
var listType = pyList.GetPythonType();
//it can convert a PyList, since PyList satisfies the python sequence protocol

Assert.IsFalse(codec.CanDecode(pyList, typeof(bool)));
Assert.IsFalse(codec.CanDecode(pyList, typeof(IList<int>)));
Assert.IsFalse(codec.CanDecode(pyList, typeof(System.Collections.IEnumerable)));
Assert.IsFalse(codec.CanDecode(pyList, typeof(IEnumerable<int>)));
Assert.IsFalse(codec.CanDecode(listType, typeof(bool)));
Assert.IsFalse(codec.CanDecode(listType, typeof(IList<int>)));
Assert.IsFalse(codec.CanDecode(listType, typeof(System.Collections.IEnumerable)));
Assert.IsFalse(codec.CanDecode(listType, typeof(IEnumerable<int>)));

Assert.IsTrue(codec.CanDecode(pyList, typeof(ICollection<float>)));
Assert.IsTrue(codec.CanDecode(pyList, typeof(ICollection<string>)));
Assert.IsTrue(codec.CanDecode(pyList, typeof(ICollection<int>)));
Assert.IsTrue(codec.CanDecode(listType, typeof(ICollection<float>)));
Assert.IsTrue(codec.CanDecode(listType, typeof(ICollection<string>)));
Assert.IsTrue(codec.CanDecode(listType, typeof(ICollection<int>)));

//convert to collection of int
ICollection<int> intCollection = null;
Expand Down Expand Up @@ -380,7 +381,7 @@ public void As_Object_AffectedByDecoders()

public class EverythingElseToSelfDecoder : IPyObjectDecoder
{
public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return targetType.IsAssignableFrom(typeof(EverythingElseToSelfDecoder));
}
Expand All @@ -399,7 +400,7 @@ public ValueErrorWrapper(string message) : base(message) { }

class ValueErrorCodec : IPyObjectEncoder, IPyObjectDecoder
{
public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
=> this.CanEncode(targetType)
&& PythonReferenceComparer.Instance.Equals(objectType, PythonEngine.Eval("ValueError"));

Expand All @@ -424,7 +425,7 @@ class InstancelessExceptionDecoder : IPyObjectDecoder
{
readonly PyObject PyErr = Py.Import("clr.interop").GetAttr("PyErr");

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
=> PythonReferenceComparer.Instance.Equals(PyErr, objectType);

public bool TryDecode<T>(PyObject pyObj, out T value)
Expand Down Expand Up @@ -466,7 +467,7 @@ public DecoderReturningPredefinedValue(PyObject objectType, TTarget decodeResult
this.DecodeResult = decodeResult;
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
=> objectType.Handle == TheOnlySupportedSourceType.Handle
&& targetType == typeof(TTarget);
public bool TryDecode<T>(PyObject pyObj, out T value)
Expand All @@ -485,7 +486,7 @@ public static void Setup()
PyObjectConversions.RegisterDecoder(new DateTimeDecoder());
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return targetType == typeof(DateTime);
}
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Codecs/DecoderGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void Add(IPyObjectDecoder item)
public void Clear() => this.decoders.Clear();

/// <inheritdoc />
public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
=> this.decoders.Any(decoder => decoder.CanDecode(objectType, targetType));
/// <inheritdoc />
public bool TryDecode<T>(PyObject pyObj, out T value)
Expand Down Expand Up @@ -58,7 +58,7 @@ public static class DecoderGroupExtensions
/// </summary>
public static IPyObjectDecoder GetDecoder(
this IPyObjectDecoder decoder,
PyObject objectType, Type targetType)
PyType objectType, Type targetType)
{
if (decoder is null) throw new ArgumentNullException(nameof(decoder));

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/Codecs/EnumPyIntCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public sealed class EnumPyIntCodec : IPyObjectEncoder, IPyObjectDecoder
{
public static EnumPyIntCodec Instance { get; } = new EnumPyIntCodec();

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return targetType.IsEnum
&& objectType.IsSubclass(new BorrowedReference(Runtime.PyLongType));
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Codecs/IterableDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ internal static bool IsIterable(Type targetType)
return targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}

internal static bool IsIterable(PyObject objectType)
internal static bool IsIterable(PyType objectType)
{
return objectType.HasAttr("__iter__");
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return IsIterable(objectType) && IsIterable(targetType);
}
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Codecs/ListDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private static bool IsList(Type targetType)
return targetType.GetGenericTypeDefinition() == typeof(IList<>);
}

private static bool IsList(PyObject objectType)
private static bool IsList(PyType objectType)
{
//TODO accept any python object that implements the sequence and list protocols
//must implement sequence protocol to fully implement list protocol
Expand All @@ -23,7 +23,7 @@ private static bool IsList(PyObject objectType)
return objectType.Handle == Runtime.PyListType;
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return IsList(objectType) && IsList(targetType);
}
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Codecs/SequenceDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static bool IsSequence(Type targetType)
return targetType.GetGenericTypeDefinition() == typeof(ICollection<>);
}

internal static bool IsSequence(PyObject objectType)
internal static bool IsSequence(PyType objectType)
{
//must implement iterable protocol to fully implement sequence protocol
if (!IterableDecoder.IsIterable(objectType)) return false;
Expand All @@ -25,7 +25,7 @@ internal static bool IsSequence(PyObject objectType)
return objectType.HasAttr("__getitem__");
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
{
return IsSequence(objectType) && IsSequence(targetType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/Codecs/TupleCodecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public PyObject TryEncode(object value)
return new PyTuple(StolenReference.DangerousFromPointer(tuple));
}

public bool CanDecode(PyObject objectType, Type targetType)
public bool CanDecode(PyType objectType, Type targetType)
=> objectType.Handle == Runtime.PyTupleType && this.CanEncode(targetType);

public bool TryDecode<T>(PyObject pyObj, out T value)
Expand Down
7 changes: 5 additions & 2 deletions src/runtime/converterextensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Python.Runtime
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Python.Runtime.Codecs;
Expand All @@ -15,7 +16,7 @@ public interface IPyObjectDecoder
/// <summary>
/// Checks if this decoder can decode from <paramref name="objectType"/> to <paramref name="targetType"/>
/// </summary>
bool CanDecode(PyObject objectType, Type targetType);
bool CanDecode(PyType objectType, Type targetType);
/// <summary>
/// Attempts do decode <paramref name="pyObj"/> into a variable of specified type
/// </summary>
Expand Down Expand Up @@ -124,7 +125,9 @@ internal static bool TryDecode(IntPtr pyHandle, IntPtr pyType, Type targetType,
static Converter.TryConvertFromPythonDelegate GetDecoder(IntPtr sourceType, Type targetType)
{
IPyObjectDecoder decoder;
using (var pyType = new PyObject(Runtime.SelfIncRef(sourceType)))
var sourceTypeRef = new BorrowedReference(sourceType);
Debug.Assert(PyType.IsType(sourceTypeRef));
using (var pyType = new PyType(sourceTypeRef, prevalidated: true))
{
lock (decoders)
{
Expand Down