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

Commit6c34d20

Browse files
committed
Add function of passing an arbitrary .NET object as the value of an
attribute of PyObject by dynamic type
1 parent6afc9e6 commit6c34d20

File tree

5 files changed

+238
-8
lines changed

5 files changed

+238
-8
lines changed

‎AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
- Sean Freitag ([@cowboygneox](https://github.com/cowboygneox))
3030
- Serge Weinstock ([@sweinst](https://github.com/sweinst))
3131
- Virgil Dupras ([@hsoft](https://github.com/hsoft))
32+
- Wenguang Yang ([@yagweb](https://github.com/yagweb))
3233
- Xavier Dupré ([@sdpython](https://github.com/sdpython))
3334
- Zane Purvis ([@zanedp](https://github.com/zanedp))
3435
- ([@ArvidJB](https://github.com/ArvidJB))

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1414
- Added XML Documentation (#349)
1515
- Added Embedded tests on Appveyor (#353)
1616
- Added PY3 settings to configuration-manager (#346)
17+
- Added function of passing an arbitrary .NET object as the value of an attribute of PyObject (#370)(#373)
1718

1819
###Changed
1920

‎src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<ProjectDefaultTargets="Build"xmlns="http://schemas.microsoft.com/developer/msbuild/2003"ToolsVersion="4.0">
33
<PropertyGroup>
44
<ConfigurationCondition=" '$(Configuration)' == ''">Debug</Configuration>
@@ -30,7 +30,8 @@
3030
<DebugType>full</DebugType>
3131
</PropertyGroup>
3232
<PropertyGroupCondition=" '$(Configuration)' == 'ReleaseMono'">
33-
<DefineConstantsCondition="'$(DefineConstants)' == ''"></DefineConstants>
33+
<DefineConstantsCondition="'$(DefineConstants)' == ''">
34+
</DefineConstants>
3435
<Optimize>true</Optimize>
3536
<DebugType>pdbonly</DebugType>
3637
</PropertyGroup>
@@ -40,7 +41,8 @@
4041
<DebugType>full</DebugType>
4142
</PropertyGroup>
4243
<PropertyGroupCondition=" '$(Configuration)' == 'ReleaseWin'">
43-
<DefineConstantsCondition="'$(DefineConstants)' == ''"></DefineConstants>
44+
<DefineConstantsCondition="'$(DefineConstants)' == ''">
45+
</DefineConstants>
4446
<Optimize>true</Optimize>
4547
<DebugType>pdbonly</DebugType>
4648
</PropertyGroup>
@@ -50,7 +52,8 @@
5052
<DebugType>full</DebugType>
5153
</PropertyGroup>
5254
<PropertyGroupCondition=" '$(Configuration)' == 'ReleaseMonoPY3'">
53-
<DefineConstantsCondition="'$(DefineConstants)' == ''"></DefineConstants>
55+
<DefineConstantsCondition="'$(DefineConstants)' == ''">
56+
</DefineConstants>
5457
<Optimize>true</Optimize>
5558
<DebugType>pdbonly</DebugType>
5659
</PropertyGroup>
@@ -60,11 +63,13 @@
6063
<DebugType>full</DebugType>
6164
</PropertyGroup>
6265
<PropertyGroupCondition=" '$(Configuration)' == 'ReleaseWinPY3'">
63-
<DefineConstantsCondition="'$(DefineConstants)' == ''"></DefineConstants>
66+
<DefineConstantsCondition="'$(DefineConstants)' == ''">
67+
</DefineConstants>
6468
<Optimize>true</Optimize>
6569
<DebugType>pdbonly</DebugType>
6670
</PropertyGroup>
6771
<ItemGroup>
72+
<ReferenceInclude="Microsoft.CSharp" />
6873
<ReferenceInclude="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
6974
<HintPath>..\..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
7075
</Reference>
@@ -76,6 +81,7 @@
7681
</ItemGroup>
7782
<ItemGroup>
7883
<CompileInclude="pyinitialize.cs" />
84+
<CompileInclude="dynamic.cs" />
7985
<CompileInclude="pyimport.cs" />
8086
<CompileInclude="pyiter.cs" />
8187
<CompileInclude="pylong.cs" />
@@ -101,4 +107,4 @@
101107
<CopySourceFiles="$(TargetAssembly)"DestinationFolder="$(PythonBuildDir)" />
102108
<CopySourceFiles="$(TargetAssemblyPdb)"Condition="Exists('$(TargetAssemblyPdb)')"DestinationFolder="$(PythonBuildDir)" />
103109
</Target>
104-
</Project>
110+
</Project>

‎src/embed_tests/dynamic.cs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
usingSystem;
2+
usingSystem.Text;
3+
usingNUnit.Framework;
4+
usingPython.Runtime;
5+
6+
namespacePython.EmbeddingTest
7+
{
8+
[TestFixture]
9+
publicclassdynamicTest
10+
{
11+
privateIntPtrgs;
12+
privateoutstreamstream;
13+
14+
[SetUp]
15+
publicvoidSetUp()
16+
{
17+
PythonEngine.Initialize();
18+
gs=PythonEngine.AcquireLock();
19+
20+
/* redirect sys.stdout to a .NET object */
21+
stream=newoutstream();
22+
}
23+
24+
[TearDown]
25+
publicvoidTearDown()
26+
{
27+
PythonEngine.ReleaseLock(gs);
28+
PythonEngine.Shutdown();
29+
}
30+
31+
/// <summary>
32+
/// Set the attribute of a pyobject to null.
33+
/// </summary>
34+
[Test]
35+
publicvoidAssignNone()
36+
{
37+
dynamicsys=Py.Import("sys");
38+
sys.stderr=null;
39+
Assert.IsNull(sys.stderr);
40+
}
41+
42+
/// <summary>
43+
/// Set the attribute of a pyobject with a .NET object.
44+
/// </summary>
45+
[Test]
46+
publicvoidAssignObject()
47+
{
48+
dynamicsys=Py.Import("sys");
49+
sys.stdout=stream;
50+
// Check whether there are the same object.
51+
Assert.AreEqual(sys.stdout,stream);
52+
53+
stream.clear();
54+
PythonEngine.RunSimpleString("print('Hello!')");
55+
Assert.AreEqual(stream.getvalue(),"Hello!\n");
56+
}
57+
58+
/// <summary>
59+
/// When the .NET object was created and used in Python side.
60+
/// </summary>
61+
/// <remarks>
62+
/// Needs Pull Request #376 in order for the exception below to show up.
63+
/// </remarks>
64+
[Test]
65+
[Ignore("System.ArgumentException : Cannot pass a GCHandle across AppDomains")]
66+
publicvoidAssignObjectInPython()
67+
{
68+
PythonEngine.RunSimpleString(
69+
"import sys\n"+
70+
"from Python.EmbeddingTest import outstream\n"+
71+
"sys.stdout = outstream()\n"
72+
);
73+
dynamicsys=Py.Import("sys");
74+
dynamicobj=sys.stdout;
75+
Assert.IsTrue(objisoutstream);
76+
}
77+
78+
/// <summary>
79+
/// Check whether we can get the attr of a python object when the value of attr is a PyObject.
80+
/// </summary>
81+
[Test]
82+
publicvoidAssignPyObject()
83+
{
84+
dynamicsys=Py.Import("sys");
85+
dynamicio=Py.Import("io");
86+
sys.stderr=io.StringIO();
87+
dynamicbb=sys.stderr;//Get the PyObject
88+
bb.write("Hello!");
89+
Assert.AreEqual(bb.getvalue().ToString(),"Hello!");
90+
}
91+
92+
/// <summary>
93+
/// Pass the .NET object in Python side.
94+
/// </summary>
95+
[Test]
96+
publicvoidPassObjectInPython()
97+
{
98+
dynamicsys=Py.Import("sys");
99+
sys.stdout=stream;
100+
101+
//Pass the .NET object in Python side
102+
PythonEngine.RunSimpleString(
103+
"import sys\n"+
104+
"from io import StringIO\n"+
105+
"sys.stderr = sys.stdout\n"
106+
);
107+
108+
//Compare in Python
109+
stream.clear();
110+
PythonEngine.RunSimpleString(
111+
"import sys\n"+
112+
"print((sys.stderr is sys.stdout))\n"
113+
);
114+
Assert.AreEqual(stream.getvalue(),"True\n");
115+
116+
//Compare in .NET
117+
Assert.AreEqual(sys.stdout,sys.stderr);
118+
}
119+
120+
/// <summary>
121+
/// Pass the PyObject in .NET side
122+
/// </summary>
123+
[Test]
124+
publicvoidPassPyObjectInNet()
125+
{
126+
dynamicsys=Py.Import("sys");
127+
sys.stdout=stream;
128+
sys.stderr=sys.stdout;
129+
130+
//Compare in Python
131+
PyObjectres=PythonEngine.RunString(
132+
"import sys\n"+
133+
"print(sys.stderr is sys.stdout)\n"
134+
);
135+
Assert.AreEqual(sys.stdout.getvalue().ToString(),"False\n");
136+
137+
//Compare in .NET
138+
Assert.AreEqual(sys.stdout,sys.stderr);
139+
}
140+
}
141+
142+
/// <summary>
143+
/// Implement the interface of the sys.stdout redirection
144+
/// </summary>
145+
publicclassoutstream
146+
{
147+
privateStringBuilderbuffer;
148+
149+
publicoutstream()
150+
{
151+
buffer=newStringBuilder();
152+
}
153+
154+
publicvoidwrite(stringstr)
155+
{
156+
buffer.Append(str);
157+
}
158+
159+
publicvoidflush()
160+
{
161+
}
162+
163+
publicvoidclose()
164+
{
165+
}
166+
167+
publicvoidclear()
168+
{
169+
buffer.Clear();
170+
}
171+
172+
publicstringgetvalue()
173+
{
174+
returnbuffer.ToString();
175+
}
176+
}
177+
}

‎src/runtime/pyobject.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,31 @@ public bool HasAttr(PyObject name)
183183
}
184184

185185

186+
/// <summary>
187+
/// GetAttr Method For Dynamic Type
188+
/// </summary>
189+
/// <remarks>
190+
/// Returns the named attribute of the Python object, or raises a
191+
/// PythonException if the attribute access fails.
192+
/// </remarks>
193+
publicobjectGetAttrDynamic(stringname)
194+
{
195+
IntPtrop=Runtime.PyObject_GetAttrString(obj,name);
196+
if(op==IntPtr.Zero)
197+
{
198+
thrownewPythonException();
199+
}
200+
if(ManagedType.IsManagedType(op))
201+
{
202+
ManagedTypemanagedMethod=ManagedType.GetManagedObject(op);
203+
if(managedMethodisCLRObject)
204+
{
205+
return((CLRObject)managedMethod).inst;
206+
}
207+
}
208+
returnCheckNone(newPyObject(op));
209+
}
210+
186211
/// <summary>
187212
/// GetAttr Method
188213
/// </summary>
@@ -275,6 +300,26 @@ public void SetAttr(string name, PyObject value)
275300
}
276301
}
277302

303+
publicvoidSetAttrDynamic(stringname,objectvalue)
304+
{
305+
if(value==null)
306+
{
307+
intr=Runtime.PyObject_SetAttrString(obj,name,Runtime.PyNone);
308+
if(r<0)
309+
{
310+
thrownewPythonException();
311+
}
312+
}
313+
elseif(valueisPyObject)
314+
{
315+
this.SetAttr(name,(PyObject)value);
316+
}
317+
else
318+
{
319+
varptr=Converter.ToPython(value,value.GetType());
320+
this.SetAttr(name,newPyObject(ptr));
321+
}
322+
}
278323

279324
/// <summary>
280325
/// SetAttr Method
@@ -891,7 +936,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object result)
891936
{
892937
if(this.HasAttr(binder.Name))
893938
{
894-
result=CheckNone(this.GetAttr(binder.Name));
939+
result=this.GetAttrDynamic(binder.Name);
895940
returntrue;
896941
}
897942
else
@@ -904,7 +949,7 @@ public override bool TrySetMember(SetMemberBinder binder, object value)
904949
{
905950
if(this.HasAttr(binder.Name))
906951
{
907-
this.SetAttr(binder.Name,(PyObject)value);
952+
this.SetAttrDynamic(binder.Name,value);
908953
returntrue;
909954
}
910955
else

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp