Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e117d60

Browse files
committed
Add several methods
add ImportScope: a scope can import variable from any scope, equivalent to python 'import * from mod' add dynamic member support add an OnDispose event remove the field ‘globals’ referring to python module put the scope class in a new file Unit test: TestThread uses scope function replacing Exec/Eval to speed up the execution.
1 parent dec39c7 commit e117d60

File tree

6 files changed

+725
-656
lines changed

6 files changed

+725
-656
lines changed

src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 3 additions & 3 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
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
33
<PropertyGroup>
44
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -98,7 +98,7 @@
9898
<Compile Include="TestPythonEngineProperties.cs" />
9999
<Compile Include="TestPyTuple.cs" />
100100
<Compile Include="TestRuntime.cs" />
101-
<Compile Include="pyscope.cs" />
101+
<Compile Include="TestPyScope.cs" />
102102
</ItemGroup>
103103
<ItemGroup>
104104
<ProjectReference Include="..\runtime\Python.Runtime.csproj">
@@ -118,4 +118,4 @@
118118
<Copy SourceFiles="$(TargetAssembly)" DestinationFolder="$(PythonBuildDir)" />
119119
<Copy SourceFiles="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" DestinationFolder="$(PythonBuildDir)" />
120120
</Target>
121-
</Project>
121+
</Project>

src/embed_tests/TestPyScope.cs

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
using System;
2+
using NUnit.Framework;
3+
using Python.Runtime;
4+
5+
namespace Python.EmbeddingTest
6+
{
7+
public class PyScopeTest
8+
{
9+
private PyScope ps;
10+
11+
[SetUp]
12+
public void SetUp()
13+
{
14+
using (Py.GIL())
15+
{
16+
ps = Py.CreateScope("test");
17+
}
18+
}
19+
20+
[TearDown]
21+
public void Dispose()
22+
{
23+
using (Py.GIL())
24+
{
25+
ps.Dispose();
26+
ps = null;
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Eval a Python expression and obtain its return value.
32+
/// </summary>
33+
[Test]
34+
public void TestEval()
35+
{
36+
using (Py.GIL())
37+
{
38+
ps.SetVariable("a", 1);
39+
var result = ps.Eval<int>("a + 2");
40+
Assert.AreEqual(3, result);
41+
}
42+
}
43+
44+
/// <summary>
45+
/// Exec Python statements and obtain the variables created.
46+
/// </summary>
47+
[Test]
48+
public void TestExec()
49+
{
50+
using (Py.GIL())
51+
{
52+
ps.SetVariable("bb", 100); //declare a global variable
53+
ps.SetVariable("cc", 10); //declare a local variable
54+
ps.Exec("aa = bb + cc + 3");
55+
var result = ps.GetVariable<int>("aa");
56+
Assert.AreEqual(113, result);
57+
}
58+
}
59+
60+
/// <summary>
61+
/// Compile an expression into an ast object;
62+
/// Execute the ast and obtain its return value.
63+
/// </summary>
64+
[Test]
65+
public void TestCompileExpression()
66+
{
67+
using (Py.GIL())
68+
{
69+
ps.SetVariable("bb", 100); //declare a global variable
70+
ps.SetVariable("cc", 10); //declare a local variable
71+
PyObject script = PythonEngine.Compile("bb + cc + 3", "", RunFlagType.Eval);
72+
var result = ps.Execute<int>(script);
73+
Assert.AreEqual(113, result);
74+
}
75+
}
76+
77+
/// <summary>
78+
/// Compile Python statements into an ast object;
79+
/// Execute the ast;
80+
/// Obtain the local variables created.
81+
/// </summary>
82+
[Test]
83+
public void TestCompileStatements()
84+
{
85+
using (Py.GIL())
86+
{
87+
ps.SetVariable("bb", 100); //declare a global variable
88+
ps.SetVariable("cc", 10); //declare a local variable
89+
PyObject script = PythonEngine.Compile("aa = bb + cc + 3", "", RunFlagType.File);
90+
ps.Execute(script);
91+
var result = ps.GetVariable<int>("aa");
92+
Assert.AreEqual(113, result);
93+
}
94+
}
95+
96+
/// <summary>
97+
/// Create a function in the scope, then the function can read variables in the scope.
98+
/// It cannot write the variables unless it uses the 'global' keyword.
99+
/// </summary>
100+
[Test]
101+
public void TestScopeFunction()
102+
{
103+
using (Py.GIL())
104+
{
105+
ps.SetVariable("bb", 100);
106+
ps.SetVariable("cc", 10);
107+
ps.Exec(
108+
"def func1():\n" +
109+
" bb = cc + 10\n");
110+
dynamic func1 = ps.GetVariable("func1");
111+
func1(); //call the function, it can be called any times
112+
var result = ps.GetVariable<int>("bb");
113+
Assert.AreEqual(100, result);
114+
115+
ps.SetVariable("bb", 100);
116+
ps.SetVariable("cc", 10);
117+
ps.Exec(
118+
"def func2():\n" +
119+
" global bb\n" +
120+
" bb = cc + 10\n");
121+
dynamic func2 = ps.GetVariable("func2");
122+
func2();
123+
result = ps.GetVariable<int>("bb");
124+
Assert.AreEqual(20, result);
125+
}
126+
}
127+
128+
/// <summary>
129+
/// Import a python module into the session.
130+
/// Equivalent to the Python "import" statement.
131+
/// </summary>
132+
[Test]
133+
public void TestImportModule()
134+
{
135+
using (Py.GIL())
136+
{
137+
dynamic sys = ps.ImportModule("sys");
138+
Assert.IsTrue(ps.ContainsVariable("sys"));
139+
140+
ps.Exec("sys.attr1 = 2");
141+
var value1 = ps.Eval<int>("sys.attr1");
142+
var value2 = (int)sys.attr1.AsManagedObject(typeof(int));
143+
Assert.AreEqual(2, value1);
144+
Assert.AreEqual(2, value2);
145+
146+
//import as
147+
ps.ImportModule("sys", "sys1");
148+
Assert.IsTrue(ps.ContainsVariable("sys1"));
149+
}
150+
}
151+
152+
/// <summary>
153+
/// Create a scope and import variables from a scope,
154+
/// exec Python statements in the scope then discard it.
155+
/// </summary>
156+
[Test]
157+
public void TestImportScope()
158+
{
159+
using (Py.GIL())
160+
{
161+
ps.SetVariable("bb", 100);
162+
ps.SetVariable("cc", 10);
163+
164+
PyScope scope = ps.CreateScope();
165+
166+
scope.Exec("aa = bb + cc + 3");
167+
var result = scope.GetVariable<int>("aa");
168+
Assert.AreEqual(113, result);
169+
170+
scope.Dispose();
171+
172+
Assert.IsFalse(ps.ContainsVariable("aa"));
173+
}
174+
}
175+
176+
/// <summary>
177+
/// Create a scope and import variables from a scope,
178+
/// call the function imported.
179+
/// </summary>
180+
[Test]
181+
public void TestImportScopeFunction()
182+
{
183+
using (Py.GIL())
184+
{
185+
ps.SetVariable("bb", 100);
186+
ps.SetVariable("cc", 10);
187+
ps.Exec(
188+
"def func1():\n" +
189+
" return cc + bb\n");
190+
191+
PyScope scope = ps.CreateScope();
192+
193+
//'func1' is imported from the origion scope
194+
scope.Exec(
195+
"def func2():\n" +
196+
" return func1() - cc - bb\n");
197+
dynamic func2 = scope.GetVariable("func2");
198+
199+
var result1 = func2().AsManagedObject(typeof(int));
200+
Assert.AreEqual(0, result1);
201+
202+
scope.SetVariable("cc", 20);//it has no effect on the globals of 'func1'
203+
var result2 = func2().AsManagedObject(typeof(int));
204+
Assert.AreEqual(-10, result2);
205+
scope.SetVariable("cc", 10); //rollback
206+
207+
ps.SetVariable("cc", 20);
208+
var result3 = func2().AsManagedObject(typeof(int));
209+
Assert.AreEqual(10, result3);
210+
ps.SetVariable("cc", 10); //rollback
211+
212+
scope.Dispose();
213+
}
214+
}
215+
216+
/// <summary>
217+
/// Import a python module into the session with a new name.
218+
/// Equivalent to the Python "import .. as .." statement.
219+
/// </summary>
220+
[Test]
221+
public void TestImportScopeByName()
222+
{
223+
using (Py.GIL())
224+
{
225+
ps.SetVariable("bb", 100);
226+
227+
var scope = Py.CreateScope();
228+
scope.ImportScope("test");
229+
230+
Assert.IsTrue(scope.ContainsVariable("bb"));
231+
}
232+
}
233+
234+
/// <summary>
235+
/// Share a pyscope by multiple threads.
236+
/// </summary>
237+
[Test]
238+
public void TestThread()
239+
{
240+
//After the proposal here https://github.com/pythonnet/pythonnet/pull/419 complished,
241+
//the BeginAllowThreads statement blow and the last EndAllowThreads statement
242+
//should be removed.
243+
dynamic _ps = ps;
244+
var ts = PythonEngine.BeginAllowThreads();
245+
using (Py.GIL())
246+
{
247+
_ps.res = 0;
248+
_ps.bb = 100;
249+
_ps.th_cnt = 0;
250+
//add function to the scope
251+
//can be call many times, more efficient than ast
252+
ps.Exec(
253+
"def update():\n" +
254+
" global res, th_cnt\n" +
255+
" res += bb + 1\n" +
256+
" th_cnt += 1\n"
257+
);
258+
}
259+
int th_cnt = 3;
260+
for (int i =0; i< th_cnt; i++)
261+
{
262+
System.Threading.Thread th = new System.Threading.Thread(()=>
263+
{
264+
using (Py.GIL())
265+
{
266+
//ps.GetVariable<dynamic>("update")(); //call the scope function dynamicly
267+
_ps.update();
268+
}
269+
});
270+
th.Start();
271+
}
272+
//equivalent to Thread.Join, make the main thread join the GIL competition
273+
int cnt = 0;
274+
while(cnt != th_cnt)
275+
{
276+
using (Py.GIL())
277+
{
278+
cnt = ps.GetVariable<int>("th_cnt");
279+
}
280+
System.Threading.Thread.Sleep(10);
281+
}
282+
using (Py.GIL())
283+
{
284+
var result = ps.GetVariable<int>("res");
285+
Assert.AreEqual(101* th_cnt, result);
286+
}
287+
PythonEngine.EndAllowThreads(ts);
288+
}
289+
}
290+
}

0 commit comments

Comments
 (0)