Skip to content

Commit f707698

Browse files
authored
Add RawProxyEncoder (#1122)
Now Python host can force raw encoding for autoconverted .NET types. Enables workaround for #514
1 parent 8522b5f commit f707698

File tree

6 files changed

+54
-11
lines changed

6 files changed

+54
-11
lines changed

src/embed_tests/CodecGroups.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ public class CodecGroups
1111
[Test]
1212
public void GetEncodersByType()
1313
{
14-
var encoder1 = new ObjectToRawProxyEncoder<Uri>();
15-
var encoder2 = new ObjectToRawProxyEncoder<Uri>();
14+
var encoder1 = new ObjectToEncoderInstanceEncoder<Uri>();
15+
var encoder2 = new ObjectToEncoderInstanceEncoder<Uri>();
1616
var group = new EncoderGroup {
17-
new ObjectToRawProxyEncoder<Tuple<int>>(),
17+
new ObjectToEncoderInstanceEncoder<Tuple<int>>(),
1818
encoder1,
1919
encoder2,
2020
};
@@ -27,8 +27,8 @@ public void GetEncodersByType()
2727
public void CanEncode()
2828
{
2929
var group = new EncoderGroup {
30-
new ObjectToRawProxyEncoder<Tuple<int>>(),
31-
new ObjectToRawProxyEncoder<Uri>(),
30+
new ObjectToEncoderInstanceEncoder<Tuple<int>>(),
31+
new ObjectToEncoderInstanceEncoder<Uri>(),
3232
};
3333

3434
Assert.IsTrue(group.CanEncode(typeof(Tuple<int>)));
@@ -39,9 +39,9 @@ public void CanEncode()
3939
[Test]
4040
public void Encodes()
4141
{
42-
var encoder0 = new ObjectToRawProxyEncoder<Tuple<int>>();
43-
var encoder1 = new ObjectToRawProxyEncoder<Uri>();
44-
var encoder2 = new ObjectToRawProxyEncoder<Uri>();
42+
var encoder0 = new ObjectToEncoderInstanceEncoder<Tuple<int>>();
43+
var encoder1 = new ObjectToEncoderInstanceEncoder<Uri>();
44+
var encoder2 = new ObjectToEncoderInstanceEncoder<Uri>();
4545
var group = new EncoderGroup {
4646
encoder0,
4747
encoder1,

src/embed_tests/Codecs.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ static void TupleRoundtripGeneric<T, TTuple>() {
8686

8787
/// <summary>
8888
/// "Decodes" only objects of exact type <typeparamref name="T"/>.
89-
/// Result is just a raw Python object proxy.
89+
/// Result is just the raw proxy to the encoder instance itself.
9090
/// </summary>
91-
class ObjectToRawProxyEncoder<T> : IPyObjectEncoder
91+
class ObjectToEncoderInstanceEncoder<T> : IPyObjectEncoder
9292
{
9393
public bool CanEncode(Type type) => type == typeof(T);
9494
public PyObject TryEncode(object value) => this.GetRawPythonProxy();

src/runtime/Codecs/RawProxyEncoder.cs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
3+
namespace Python.Runtime.Codecs
4+
{
5+
/// <summary>
6+
/// A .NET object encoder, that returns raw proxies (e.g. no conversion to Python types).
7+
/// <para>You must inherit from this class and override <see cref="CanEncode"/>.</para>
8+
/// </summary>
9+
[Obsolete(Util.UnstableApiMessage)]
10+
public class RawProxyEncoder: IPyObjectEncoder
11+
{
12+
public PyObject TryEncode(object value)
13+
{
14+
if (value is null) throw new ArgumentNullException(nameof(value));
15+
16+
return value.GetRawPythonProxy();
17+
}
18+
19+
public virtual bool CanEncode(Type type) => false;
20+
}
21+
}

src/runtime/Python.Runtime.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<ItemGroup>
7979
<Compile Include="Codecs\EncoderGroup.cs" />
8080
<Compile Include="Codecs\DecoderGroup.cs" />
81+
<Compile Include="Codecs\RawProxyEncoder.cs" />
8182
<Compile Include="Codecs\TupleCodecs.cs" />
8283
<Compile Include="converterextensions.cs" />
8384
<Compile Include="finalizer.cs" />

src/testing/conversiontest.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
namespace Python.Test
22
{
3+
using System.Collections.Generic;
4+
35
/// <summary>
4-
/// Supports units tests for field access.
6+
/// Supports unit tests for field access.
57
/// </summary>
68
public class ConversionTest
79
{
@@ -32,6 +34,7 @@ public ConversionTest()
3234

3335
public byte[] ByteArrayField;
3436
public sbyte[] SByteArrayField;
37+
public readonly List<int> ListField = new List<int>();
3538

3639
public T? Echo<T>(T? arg) where T: struct {
3740
return arg;

src/tests/test_conversion.py

+18
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import System
77
import pytest
88
from Python.Test import ConversionTest, UnicodeString
9+
from Python.Runtime import PyObjectConversions
10+
from Python.Runtime.Codecs import RawProxyEncoder
911

1012
from ._compat import indexbytes, long, unichr, text_type, PY2, PY3
1113

@@ -700,3 +702,19 @@ def test_sbyte_array_conversion():
700702
array = ob.SByteArrayField
701703
for i, _ in enumerate(value):
702704
assert array[i] == indexbytes(value, i)
705+
706+
def test_codecs():
707+
"""Test codec registration from Python"""
708+
class ListAsRawEncoder(RawProxyEncoder):
709+
__namespace__ = "Python.Test"
710+
def CanEncode(self, clr_type):
711+
return clr_type.Name == "List`1" and clr_type.Namespace == "System.Collections.Generic"
712+
713+
list_raw_encoder = ListAsRawEncoder()
714+
PyObjectConversions.RegisterEncoder(list_raw_encoder)
715+
716+
ob = ConversionTest()
717+
718+
l = ob.ListField
719+
l.Add(42)
720+
assert ob.ListField.Count == 1

0 commit comments

Comments
 (0)