Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Jul 22, 2023. It is now read-only.
/pythonnetPublic archive
forked frompythonnet/pythonnet

Commit555f562

Browse files
authored
Codec groups: EncoderGroup and DecoderGroup (pythonnet#1085)
* Added Codecs: EncoderGroup and DecoderGroupThese classes would help to manage codec layers. For example, a library could register its own codecs, but also allow anyone to inject their codecs before library's own:public static EncoderGroup BeforeLibraryEncoders { get; } = new EncoderGroup();void LibraryRegisterCodecs(){ PyObjectConversions.RegisterEncoder(BeforeLibraryEncoders); PyObjectConversions.RegisterEncoder(LibraryEncoder.Instance);}Then in a program using that library:Library.BeforeLibraryEncoders.Encoders.Add(preencoder);
1 parent92bc145 commit555f562

File tree

7 files changed

+334
-4
lines changed

7 files changed

+334
-4
lines changed

‎src/embed_tests/CodecGroups.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
namespacePython.EmbeddingTest
2+
{
3+
usingSystem;
4+
usingSystem.Linq;
5+
usingNUnit.Framework;
6+
usingPython.Runtime;
7+
usingPython.Runtime.Codecs;
8+
9+
publicclassCodecGroups
10+
{
11+
[Test]
12+
publicvoidGetEncodersByType()
13+
{
14+
varencoder1=newObjectToRawProxyEncoder<Uri>();
15+
varencoder2=newObjectToRawProxyEncoder<Uri>();
16+
vargroup=newEncoderGroup{
17+
newObjectToRawProxyEncoder<Tuple<int>>(),
18+
encoder1,
19+
encoder2,
20+
};
21+
22+
vargot=group.GetEncoders(typeof(Uri)).ToArray();
23+
CollectionAssert.AreEqual(new[]{encoder1,encoder2},got);
24+
}
25+
26+
[Test]
27+
publicvoidCanEncode()
28+
{
29+
vargroup=newEncoderGroup{
30+
newObjectToRawProxyEncoder<Tuple<int>>(),
31+
newObjectToRawProxyEncoder<Uri>(),
32+
};
33+
34+
Assert.IsTrue(group.CanEncode(typeof(Tuple<int>)));
35+
Assert.IsTrue(group.CanEncode(typeof(Uri)));
36+
Assert.IsFalse(group.CanEncode(typeof(string)));
37+
}
38+
39+
[Test]
40+
publicvoidEncodes()
41+
{
42+
varencoder0=newObjectToRawProxyEncoder<Tuple<int>>();
43+
varencoder1=newObjectToRawProxyEncoder<Uri>();
44+
varencoder2=newObjectToRawProxyEncoder<Uri>();
45+
vargroup=newEncoderGroup{
46+
encoder0,
47+
encoder1,
48+
encoder2,
49+
};
50+
51+
varuri=group.TryEncode(newUri("data:"));
52+
varclrObject=(CLRObject)ManagedType.GetManagedObject(uri.Handle);
53+
Assert.AreSame(encoder1,clrObject.inst);
54+
Assert.AreNotSame(encoder2,clrObject.inst);
55+
56+
vartuple=group.TryEncode(Tuple.Create(1));
57+
clrObject=(CLRObject)ManagedType.GetManagedObject(tuple.Handle);
58+
Assert.AreSame(encoder0,clrObject.inst);
59+
}
60+
61+
[Test]
62+
publicvoidGetDecodersByTypes()
63+
{
64+
varpyint=newPyInt(10).GetPythonType();
65+
varpyfloat=newPyFloat(10).GetPythonType();
66+
varpystr=newPyString("world").GetPythonType();
67+
vardecoder1=newDecoderReturningPredefinedValue<long>(pyint,decodeResult:42);
68+
vardecoder2=newDecoderReturningPredefinedValue<string>(pyfloat,decodeResult:"atad:");
69+
vargroup=newDecoderGroup{
70+
decoder1,
71+
decoder2,
72+
};
73+
74+
vardecoder=group.GetDecoder(pyfloat,typeof(string));
75+
Assert.AreSame(decoder2,decoder);
76+
decoder=group.GetDecoder(pystr,typeof(string));
77+
Assert.IsNull(decoder);
78+
decoder=group.GetDecoder(pyint,typeof(long));
79+
Assert.AreSame(decoder1,decoder);
80+
}
81+
[Test]
82+
publicvoidCanDecode()
83+
{
84+
varpyint=newPyInt(10).GetPythonType();
85+
varpyfloat=newPyFloat(10).GetPythonType();
86+
varpystr=newPyString("world").GetPythonType();
87+
vardecoder1=newDecoderReturningPredefinedValue<long>(pyint,decodeResult:42);
88+
vardecoder2=newDecoderReturningPredefinedValue<string>(pyfloat,decodeResult:"atad:");
89+
vargroup=newDecoderGroup{
90+
decoder1,
91+
decoder2,
92+
};
93+
94+
Assert.IsTrue(group.CanDecode(pyint,typeof(long)));
95+
Assert.IsFalse(group.CanDecode(pyint,typeof(int)));
96+
Assert.IsTrue(group.CanDecode(pyfloat,typeof(string)));
97+
Assert.IsFalse(group.CanDecode(pystr,typeof(string)));
98+
}
99+
100+
[Test]
101+
publicvoidDecodes()
102+
{
103+
varpyint=newPyInt(10).GetPythonType();
104+
varpyfloat=newPyFloat(10).GetPythonType();
105+
vardecoder1=newDecoderReturningPredefinedValue<long>(pyint,decodeResult:42);
106+
vardecoder2=newDecoderReturningPredefinedValue<string>(pyfloat,decodeResult:"atad:");
107+
vargroup=newDecoderGroup{
108+
decoder1,
109+
decoder2,
110+
};
111+
112+
Assert.IsTrue(group.TryDecode(newPyInt(10),outlonglongResult));
113+
Assert.AreEqual(42,longResult);
114+
Assert.IsTrue(group.TryDecode(newPyFloat(10),outstringstrResult));
115+
Assert.AreSame("atad:",strResult);
116+
117+
Assert.IsFalse(group.TryDecode(newPyInt(10),outint_));
118+
}
119+
120+
[SetUp]
121+
publicvoidSetUp()
122+
{
123+
PythonEngine.Initialize();
124+
}
125+
126+
[TearDown]
127+
publicvoidDispose()
128+
{
129+
PythonEngine.Shutdown();
130+
}
131+
}
132+
}

‎src/embed_tests/Codecs.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,41 @@ static void TupleRoundtripGeneric<T, TTuple>() {
8383
}
8484
}
8585
}
86+
87+
/// <summary>
88+
/// "Decodes" only objects of exact type <typeparamref name="T"/>.
89+
/// Result is just a raw Python object proxy.
90+
/// </summary>
91+
classObjectToRawProxyEncoder<T>:IPyObjectEncoder
92+
{
93+
publicboolCanEncode(Typetype)=>type==typeof(T);
94+
publicPyObjectTryEncode(objectvalue)=>this.GetRawPythonProxy();
95+
}
96+
97+
/// <summary>
98+
/// Decodes object of specified Python type to the predefined value <see cref="DecodeResult"/>
99+
/// </summary>
100+
/// <typeparam name="TTarget">Type of the <see cref="DecodeResult"/></typeparam>
101+
classDecoderReturningPredefinedValue<TTarget>:IPyObjectDecoder
102+
{
103+
publicPyObjectTheOnlySupportedSourceType{get;}
104+
publicTTargetDecodeResult{get;}
105+
106+
publicDecoderReturningPredefinedValue(PyObjectobjectType,TTargetdecodeResult)
107+
{
108+
this.TheOnlySupportedSourceType=objectType;
109+
this.DecodeResult=decodeResult;
110+
}
111+
112+
publicboolCanDecode(PyObjectobjectType,TypetargetType)
113+
=>objectType.Handle==TheOnlySupportedSourceType.Handle
114+
&&targetType==typeof(TTarget);
115+
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
116+
{
117+
if(typeof(T)!=typeof(TTarget))
118+
thrownewArgumentException(nameof(T));
119+
value=(T)(object)DecodeResult;
120+
returntrue;
121+
}
122+
}
86123
}

‎src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<NoneInclude="packages.config" />
8484
</ItemGroup>
8585
<ItemGroup>
86+
<CompileInclude="CodecGroups.cs" />
8687
<CompileInclude="Codecs.cs" />
8788
<CompileInclude="dynamic.cs" />
8889
<CompileInclude="pyimport.cs" />

‎src/runtime/Codecs/DecoderGroup.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
namespacePython.Runtime.Codecs
2+
{
3+
usingSystem;
4+
usingSystem.Collections;
5+
usingSystem.Collections.Generic;
6+
usingSystem.Linq;
7+
8+
/// <summary>
9+
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
10+
/// </summary>
11+
[Obsolete(Util.UnstableApiMessage)]
12+
publicsealedclassDecoderGroup:IPyObjectDecoder,IEnumerable<IPyObjectDecoder>
13+
{
14+
readonlyList<IPyObjectDecoder>decoders=newList<IPyObjectDecoder>();
15+
16+
/// <summary>
17+
/// Add specified decoder to the group
18+
/// </summary>
19+
publicvoidAdd(IPyObjectDecoderitem)
20+
{
21+
if(itemisnull)thrownewArgumentNullException(nameof(item));
22+
23+
this.decoders.Add(item);
24+
}
25+
/// <summary>
26+
/// Remove all decoders from the group
27+
/// </summary>
28+
publicvoidClear()=>this.decoders.Clear();
29+
30+
/// <inheritdoc />
31+
publicboolCanDecode(PyObjectobjectType,TypetargetType)
32+
=>this.decoders.Any(decoder=>decoder.CanDecode(objectType,targetType));
33+
/// <inheritdoc />
34+
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
35+
{
36+
if(pyObjisnull)thrownewArgumentNullException(nameof(pyObj));
37+
38+
vardecoder=this.GetDecoder(pyObj.GetPythonType(),typeof(T));
39+
if(decoderisnull)
40+
{
41+
value=default;
42+
returnfalse;
43+
}
44+
returndecoder.TryDecode(pyObj,outvalue);
45+
}
46+
47+
/// <inheritdoc />
48+
publicIEnumerator<IPyObjectDecoder>GetEnumerator()=>this.decoders.GetEnumerator();
49+
IEnumeratorIEnumerable.GetEnumerator()=>this.decoders.GetEnumerator();
50+
}
51+
52+
[Obsolete(Util.UnstableApiMessage)]
53+
publicstaticclassDecoderGroupExtensions
54+
{
55+
/// <summary>
56+
/// Gets a concrete instance of <see cref="IPyObjectDecoder"/>
57+
/// (potentially selecting one from a collection),
58+
/// that can decode from <paramref name="objectType"/> to <paramref name="targetType"/>,
59+
/// or <c>null</c> if a matching decoder can not be found.
60+
/// </summary>
61+
[Obsolete(Util.UnstableApiMessage)]
62+
publicstaticIPyObjectDecoderGetDecoder(
63+
thisIPyObjectDecoderdecoder,
64+
PyObjectobjectType,TypetargetType)
65+
{
66+
if(decoderisnull)thrownewArgumentNullException(nameof(decoder));
67+
68+
if(decoderisIEnumerable<IPyObjectDecoder>composite)
69+
{
70+
returncomposite
71+
.Select(nestedDecoder=>nestedDecoder.GetDecoder(objectType,targetType))
72+
.FirstOrDefault(d=>d!=null);
73+
}
74+
75+
returndecoder.CanDecode(objectType,targetType)?decoder:null;
76+
}
77+
}
78+
}

‎src/runtime/Codecs/EncoderGroup.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
namespacePython.Runtime.Codecs
2+
{
3+
usingSystem;
4+
usingSystem.Collections;
5+
usingSystem.Collections.Generic;
6+
usingSystem.Linq;
7+
8+
/// <summary>
9+
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
10+
/// </summary>
11+
[Obsolete(Util.UnstableApiMessage)]
12+
publicsealedclassEncoderGroup:IPyObjectEncoder,IEnumerable<IPyObjectEncoder>
13+
{
14+
readonlyList<IPyObjectEncoder>encoders=newList<IPyObjectEncoder>();
15+
16+
/// <summary>
17+
/// Add specified encoder to the group
18+
/// </summary>
19+
publicvoidAdd(IPyObjectEncoderitem)
20+
{
21+
if(itemisnull)thrownewArgumentNullException(nameof(item));
22+
this.encoders.Add(item);
23+
}
24+
/// <summary>
25+
/// Remove all encoders from the group
26+
/// </summary>
27+
publicvoidClear()=>this.encoders.Clear();
28+
29+
/// <inheritdoc />
30+
publicboolCanEncode(Typetype)=>this.encoders.Any(encoder=>encoder.CanEncode(type));
31+
/// <inheritdoc />
32+
publicPyObjectTryEncode(objectvalue)
33+
{
34+
if(valueisnull)thrownewArgumentNullException(nameof(value));
35+
36+
foreach(varencoderinthis.GetEncoders(value.GetType()))
37+
{
38+
varresult=encoder.TryEncode(value);
39+
if(result!=null)
40+
{
41+
returnresult;
42+
}
43+
}
44+
45+
returnnull;
46+
}
47+
48+
/// <inheritdoc />
49+
publicIEnumerator<IPyObjectEncoder>GetEnumerator()=>this.encoders.GetEnumerator();
50+
IEnumeratorIEnumerable.GetEnumerator()=>this.encoders.GetEnumerator();
51+
}
52+
53+
[Obsolete(Util.UnstableApiMessage)]
54+
publicstaticclassEncoderGroupExtensions
55+
{
56+
/// <summary>
57+
/// Gets specific instances of <see cref="IPyObjectEncoder"/>
58+
/// (potentially selecting one from a collection),
59+
/// that can encode the specified <paramref name="type"/>.
60+
/// </summary>
61+
[Obsolete(Util.UnstableApiMessage)]
62+
publicstaticIEnumerable<IPyObjectEncoder>GetEncoders(thisIPyObjectEncoderdecoder,Typetype)
63+
{
64+
if(decoderisnull)thrownewArgumentNullException(nameof(decoder));
65+
66+
if(decoderisIEnumerable<IPyObjectEncoder>composite)
67+
{
68+
foreach(varnestedEncoderincomposite)
69+
foreach(varmatchinnestedEncoder.GetEncoders(type))
70+
{
71+
yieldreturnmatch;
72+
}
73+
}elseif(decoder.CanEncode(type))
74+
{
75+
yieldreturndecoder;
76+
}
77+
}
78+
}
79+
}

‎src/runtime/Python.Runtime.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
<ReferenceInclude="System" />
7777
</ItemGroup>
7878
<ItemGroup>
79+
<CompileInclude="Codecs\EncoderGroup.cs" />
80+
<CompileInclude="Codecs\DecoderGroup.cs" />
7981
<CompileInclude="Codecs\TupleCodecs.cs" />
8082
<CompileInclude="converterextensions.cs" />
8183
<CompileInclude="finalizer.cs" />

‎src/runtime/converterextensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Python.Runtime
55
usingSystem.Collections.Generic;
66
usingSystem.Linq;
77
usingSystem.Reflection;
8+
usingPython.Runtime.Codecs;
89

910
/// <summary>
1011
/// Defines <see cref="PyObject"/> conversion to CLR types (unmarshalling)
@@ -49,8 +50,8 @@ public interface IPyObjectEncoder
4950
[Obsolete(Util.UnstableApiMessage)]
5051
publicstaticclassPyObjectConversions
5152
{
52-
staticreadonlyList<IPyObjectDecoder>decoders=newList<IPyObjectDecoder>();
53-
staticreadonlyList<IPyObjectEncoder>encoders=newList<IPyObjectEncoder>();
53+
staticreadonlyDecoderGroupdecoders=newDecoderGroup();
54+
staticreadonlyEncoderGroupencoders=newEncoderGroup();
5455

5556
/// <summary>
5657
/// Registers specified encoder (marshaller)
@@ -101,7 +102,7 @@ static IPyObjectEncoder[] GetEncoders(Type type)
101102
{
102103
lock(encoders)
103104
{
104-
returnencoders.Where(encoder=>encoder.CanEncode(type)).ToArray();
105+
returnencoders.GetEncoders(type).ToArray();
105106
}
106107
}
107108
#endregion
@@ -128,7 +129,7 @@ static Converter.TryConvertFromPythonDelegate GetDecoder(IntPtr sourceType, Type
128129
{
129130
lock(decoders)
130131
{
131-
decoder=decoders.Find(d=>d.CanDecode(pyType,targetType));
132+
decoder=decoders.GetDecoder(pyType,targetType);
132133
if(decoder==null)returnnull;
133134
}
134135
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp