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

Commited03682

Browse files
yagwebtestrunner123
authored andcommitted
add a scope class to manage the context of interaction with Python an… (pythonnet#381)
* add a scope class to manage the context of interaction with Python and simplify the variable exchanging* Deprecate public RunStringHad to remove defaults to disambiguate call on `internal RunString`.Can re-add after removing `public RunString`Closespythonnet#401* Rename several methods and add three methodsReferring to IronPython, change the name of the methods Get, Exists, SetLocal, DelLocal to GetVariable, ContainsVariable, SetVariable, RemoveVariable.Hidden the methods SetGlobalVariable, RemoveGlobalVariable.Add a new method 'Compile' to compile string into ast, the ast can be seen as the ScriptSource of IronPython.Add two new methods 'Execute' and 'Execute<T>' to execute an ast andobtain the result, corresponding to the 'Execute' method of IronPython.* rebased* Rebased update* format cleanup* create unnamed pyscope, make PyScope.GILState saveremove method GetInstHandleadd function to create unnamed pyscopeadd a field isDisposed for PyScope.GILState to make it more save* fixup! create unnamed pyscope, make PyScope.GILState save* remove GIL and rebased* Add several methodsadd ImportScope: a scope can import variable from any scope, equivalent topython 'import * from mod'add dynamic member supportadd an OnDispose eventremove the field ‘globals’ referring to python moduleput the scope class in a new fileUnit test:TestThread uses scope function replacing Exec/Eval to speed up the execution.* add a Variables method* fixup! add a Variables method* remove private method _GetVariable* add unit test for Variables() method* add several methods and rebasedAdd an optional dict parameter for Eval/Exec/Execute methodsAdd a new field obj which point to a Python Module (same as pyobject)Add a static method NewRename the old ImportScope method to ImportAllFromScopeAdd a new ImportScope method and add a unit test for itRename the CreateScope method to NewScope* add a new class PyScopeManager* cleaned up the Import methods* updated according to filmor's comments* fixup! updated according to filmor's comments* Get/Set Methods renamed
1 parent5474bed commited03682

File tree

7 files changed

+1074
-1
lines changed

7 files changed

+1074
-1
lines changed

‎src/embed_tests/Python.EmbeddingTest.csproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<CompileInclude="TestNamedArguments.cs" />
101101
<CompileInclude="TestPyWith.cs" />
102102
<CompileInclude="TestRuntime.cs" />
103+
<CompileInclude="TestPyScope.cs" />
103104
</ItemGroup>
104105
<ItemGroup>
105106
<ProjectReferenceInclude="..\runtime\Python.Runtime.csproj">

‎src/embed_tests/TestPyScope.cs‎

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
usingSystem;
2+
usingNUnit.Framework;
3+
usingPython.Runtime;
4+
5+
namespacePython.EmbeddingTest
6+
{
7+
publicclassPyScopeTest
8+
{
9+
privatePyScopeps;
10+
11+
[SetUp]
12+
publicvoidSetUp()
13+
{
14+
using(Py.GIL())
15+
{
16+
ps=Py.CreateScope("test");
17+
}
18+
}
19+
20+
[TearDown]
21+
publicvoidDispose()
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+
publicvoidTestEval()
35+
{
36+
using(Py.GIL())
37+
{
38+
ps.Set("a",1);
39+
varresult=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+
publicvoidTestExec()
49+
{
50+
using(Py.GIL())
51+
{
52+
ps.Set("bb",100);//declare a global variable
53+
ps.Set("cc",10);//declare a local variable
54+
ps.Exec("aa = bb + cc + 3");
55+
varresult=ps.Get<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+
publicvoidTestCompileExpression()
66+
{
67+
using(Py.GIL())
68+
{
69+
ps.Set("bb",100);//declare a global variable
70+
ps.Set("cc",10);//declare a local variable
71+
PyObjectscript=PythonEngine.Compile("bb + cc + 3","",RunFlagType.Eval);
72+
varresult=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+
publicvoidTestCompileStatements()
84+
{
85+
using(Py.GIL())
86+
{
87+
ps.Set("bb",100);//declare a global variable
88+
ps.Set("cc",10);//declare a local variable
89+
PyObjectscript=PythonEngine.Compile("aa = bb + cc + 3","",RunFlagType.File);
90+
ps.Execute(script);
91+
varresult=ps.Get<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+
publicvoidTestScopeFunction()
102+
{
103+
using(Py.GIL())
104+
{
105+
ps.Set("bb",100);
106+
ps.Set("cc",10);
107+
ps.Exec(
108+
"def func1():\n"+
109+
" bb = cc + 10\n");
110+
dynamicfunc1=ps.Get("func1");
111+
func1();//call the function, it can be called any times
112+
varresult=ps.Get<int>("bb");
113+
Assert.AreEqual(100,result);
114+
115+
ps.Set("bb",100);
116+
ps.Set("cc",10);
117+
ps.Exec(
118+
"def func2():\n"+
119+
" global bb\n"+
120+
" bb = cc + 10\n");
121+
dynamicfunc2=ps.Get("func2");
122+
func2();
123+
result=ps.Get<int>("bb");
124+
Assert.AreEqual(20,result);
125+
}
126+
}
127+
128+
/// <summary>
129+
/// Create a class in the scope, the class can read variables in the scope.
130+
/// Its methods can write the variables with the help of 'global' keyword.
131+
/// </summary>
132+
[Test]
133+
publicvoidTestScopeClass()
134+
{
135+
using(Py.GIL())
136+
{
137+
dynamic_ps=ps;
138+
_ps.bb=100;
139+
ps.Exec(
140+
"class Class1():\n"+
141+
" def __init__(self, value):\n"+
142+
" self.value = value\n"+
143+
" def call(self, arg):\n"+
144+
" return self.value + bb + arg\n"+//use scope variables
145+
" def update(self, arg):\n"+
146+
" global bb\n"+
147+
" bb = self.value + arg\n"//update scope variable
148+
);
149+
dynamicobj1=_ps.Class1(20);
150+
varresult=obj1.call(10).As<int>();
151+
Assert.AreEqual(130,result);
152+
153+
obj1.update(10);
154+
result=ps.Get<int>("bb");
155+
Assert.AreEqual(30,result);
156+
}
157+
}
158+
159+
/// <summary>
160+
/// Import a python module into the session.
161+
/// Equivalent to the Python "import" statement.
162+
/// </summary>
163+
[Test]
164+
publicvoidTestImportModule()
165+
{
166+
using(Py.GIL())
167+
{
168+
dynamicsys=ps.Import("sys");
169+
Assert.IsTrue(ps.Contains("sys"));
170+
171+
ps.Exec("sys.attr1 = 2");
172+
varvalue1=ps.Eval<int>("sys.attr1");
173+
varvalue2=sys.attr1.As<int>();
174+
Assert.AreEqual(2,value1);
175+
Assert.AreEqual(2,value2);
176+
177+
//import as
178+
ps.Import("sys","sys1");
179+
Assert.IsTrue(ps.Contains("sys1"));
180+
}
181+
}
182+
183+
/// <summary>
184+
/// Create a scope and import variables from a scope,
185+
/// exec Python statements in the scope then discard it.
186+
/// </summary>
187+
[Test]
188+
publicvoidTestImportScope()
189+
{
190+
using(Py.GIL())
191+
{
192+
ps.Set("bb",100);
193+
ps.Set("cc",10);
194+
195+
using(varscope=Py.CreateScope())
196+
{
197+
scope.Import(ps,"ps");
198+
scope.Exec("aa = ps.bb + ps.cc + 3");
199+
varresult=scope.Get<int>("aa");
200+
Assert.AreEqual(113,result);
201+
}
202+
203+
Assert.IsFalse(ps.Contains("aa"));
204+
}
205+
}
206+
207+
/// <summary>
208+
/// Create a scope and import variables from a scope,
209+
/// exec Python statements in the scope then discard it.
210+
/// </summary>
211+
[Test]
212+
publicvoidTestImportAllFromScope()
213+
{
214+
using(Py.GIL())
215+
{
216+
ps.Set("bb",100);
217+
ps.Set("cc",10);
218+
219+
using(varscope=ps.NewScope())
220+
{
221+
scope.Exec("aa = bb + cc + 3");
222+
varresult=scope.Get<int>("aa");
223+
Assert.AreEqual(113,result);
224+
}
225+
226+
Assert.IsFalse(ps.Contains("aa"));
227+
}
228+
}
229+
230+
/// <summary>
231+
/// Create a scope and import variables from a scope,
232+
/// call the function imported.
233+
/// </summary>
234+
[Test]
235+
publicvoidTestImportScopeFunction()
236+
{
237+
using(Py.GIL())
238+
{
239+
ps.Set("bb",100);
240+
ps.Set("cc",10);
241+
ps.Exec(
242+
"def func1():\n"+
243+
" return cc + bb\n");
244+
245+
using(PyScopescope=ps.NewScope())
246+
{
247+
//'func1' is imported from the origion scope
248+
scope.Exec(
249+
"def func2():\n"+
250+
" return func1() - cc - bb\n");
251+
dynamicfunc2=scope.Get("func2");
252+
253+
varresult1=func2().As<int>();
254+
Assert.AreEqual(0,result1);
255+
256+
scope.Set("cc",20);//it has no effect on the globals of 'func1'
257+
varresult2=func2().As<int>();
258+
Assert.AreEqual(-10,result2);
259+
scope.Set("cc",10);//rollback
260+
261+
ps.Set("cc",20);
262+
varresult3=func2().As<int>();
263+
Assert.AreEqual(10,result3);
264+
ps.Set("cc",10);//rollback
265+
}
266+
}
267+
}
268+
269+
/// <summary>
270+
/// Import a python module into the session with a new name.
271+
/// Equivalent to the Python "import .. as .." statement.
272+
/// </summary>
273+
[Test]
274+
publicvoidTestImportScopeByName()
275+
{
276+
using(Py.GIL())
277+
{
278+
ps.Set("bb",100);
279+
280+
using(varscope=Py.CreateScope())
281+
{
282+
scope.ImportAll("test");
283+
//scope.ImportModule("test");
284+
285+
Assert.IsTrue(scope.Contains("bb"));
286+
}
287+
}
288+
}
289+
290+
/// <summary>
291+
/// Use the locals() and globals() method just like in python module
292+
/// </summary>
293+
[Test]
294+
publicvoidTestVariables()
295+
{
296+
(ps.Variables()asdynamic)["ee"]=newPyInt(200);
297+
vara0=ps.Get<int>("ee");
298+
Assert.AreEqual(200,a0);
299+
300+
ps.Exec("locals()['ee'] = 210");
301+
vara1=ps.Get<int>("ee");
302+
Assert.AreEqual(210,a1);
303+
304+
ps.Exec("globals()['ee'] = 220");
305+
vara2=ps.Get<int>("ee");
306+
Assert.AreEqual(220,a2);
307+
308+
using(varitem=ps.Variables())
309+
{
310+
item["ee"]=newPyInt(230);
311+
}
312+
vara3=ps.Get<int>("ee");
313+
Assert.AreEqual(230,a3);
314+
}
315+
316+
/// <summary>
317+
/// Share a pyscope by multiple threads.
318+
/// </summary>
319+
[Test]
320+
publicvoidTestThread()
321+
{
322+
//After the proposal here https://github.com/pythonnet/pythonnet/pull/419 complished,
323+
//the BeginAllowThreads statement blow and the last EndAllowThreads statement
324+
//should be removed.
325+
dynamic_ps=ps;
326+
varts=PythonEngine.BeginAllowThreads();
327+
using(Py.GIL())
328+
{
329+
_ps.res=0;
330+
_ps.bb=100;
331+
_ps.th_cnt=0;
332+
//add function to the scope
333+
//can be call many times, more efficient than ast
334+
ps.Exec(
335+
"def update():\n"+
336+
" global res, th_cnt\n"+
337+
" res += bb + 1\n"+
338+
" th_cnt += 1\n"
339+
);
340+
}
341+
intth_cnt=3;
342+
for(inti=0;i<th_cnt;i++)
343+
{
344+
System.Threading.Threadth=newSystem.Threading.Thread(()=>
345+
{
346+
using(Py.GIL())
347+
{
348+
//ps.GetVariable<dynamic>("update")(); //call the scope function dynamicly
349+
_ps.update();
350+
}
351+
});
352+
th.Start();
353+
}
354+
//equivalent to Thread.Join, make the main thread join the GIL competition
355+
intcnt=0;
356+
while(cnt!=th_cnt)
357+
{
358+
using(Py.GIL())
359+
{
360+
cnt=ps.Get<int>("th_cnt");
361+
}
362+
System.Threading.Thread.Sleep(10);
363+
}
364+
using(Py.GIL())
365+
{
366+
varresult=ps.Get<int>("res");
367+
Assert.AreEqual(101*th_cnt,result);
368+
}
369+
PythonEngine.EndAllowThreads(ts);
370+
}
371+
}
372+
}

‎src/runtime/Python.Runtime.csproj‎

Lines changed: 2 additions & 1 deletion
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>
@@ -127,6 +127,7 @@
127127
<CompileInclude="pylong.cs" />
128128
<CompileInclude="pynumber.cs" />
129129
<CompileInclude="pyobject.cs" />
130+
<CompileInclude="pyscope.cs" />
130131
<CompileInclude="pysequence.cs" />
131132
<CompileInclude="pystring.cs" />
132133
<CompileInclude="pythonengine.cs" />

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2026 Movatter.jp