11using System ;
2- using System . CodeDom . Compiler ;
3- using System . Collections . Generic ;
42using System . Diagnostics ;
5- using System . IO ;
6- using System . Linq ;
73using System . Reflection ;
84using NUnit . Framework ;
95using Python . Runtime ;
@@ -54,6 +50,7 @@ class TestDomainReload
5450 [ Test ]
5551 public static void DomainReloadAndGC ( )
5652 {
53+ Assert . IsFalse ( PythonEngine . IsInitialized ) ;
5754 RunAssemblyAndUnload ( "test1" ) ;
5855
5956 Assert . That ( Runtime . Runtime . Py_IsInitialized ( ) != 0 ,
@@ -65,72 +62,47 @@ public static void DomainReloadAndGC()
6562 [ Test ]
6663 public static void CrossDomainObject ( )
6764 {
68- IntPtr handle ;
65+ IntPtr handle = IntPtr . Zero ;
6966 Type type = typeof ( Proxy ) ;
7067 {
7168 AppDomain domain = CreateDomain ( "test_domain_reload" ) ;
72- var theProxy = ( Proxy ) domain . CreateInstanceAndUnwrap (
73- type . Assembly . FullName ,
74- type . FullName ) ;
75- theProxy . Call ( "InitPython" , ShutdownMode . Reload ) ;
76- handle = ( IntPtr ) theProxy . Call ( "GetTestObject" ) ;
77- theProxy . Call ( "ShutdownPython" ) ;
78- AppDomain . Unload ( domain ) ;
69+ try
70+ {
71+ var theProxy = ( Proxy ) domain . CreateInstanceAndUnwrap (
72+ type . Assembly . FullName ,
73+ type . FullName ) ;
74+ theProxy . Call ( "InitPython" , ShutdownMode . Reload ) ;
75+ handle = ( IntPtr ) theProxy . Call ( "GetTestObject" ) ;
76+ theProxy . Call ( "ShutdownPython" ) ;
77+ }
78+ finally
79+ {
80+ AppDomain . Unload ( domain ) ;
81+ }
7982 }
8083
8184 {
8285 AppDomain domain = CreateDomain ( "test_domain_reload" ) ;
83- var theProxy = ( Proxy ) domain . CreateInstanceAndUnwrap (
84- type . Assembly . FullName ,
85- type . FullName ) ;
86- theProxy . Call ( "InitPython" , ShutdownMode . Reload ) ;
87-
88- // handle refering a clr object created in previous domain,
89- // it should had been deserialized and became callable agian.
90- theProxy . Call ( "RunTestObject" , handle ) ;
91- theProxy . Call ( "ShutdownPythonCompletely" ) ;
92- AppDomain . Unload ( domain ) ;
93- }
94- Assert . IsTrue ( Runtime . Runtime . Py_IsInitialized ( ) == 0 ) ;
95- }
96-
97- /// <summary>
98- /// Build an assembly out of the source code above.
99- ///
100- /// This creates a file <paramref name="assemblyName"/>.dll in order
101- /// to support the statement "proxy.theAssembly = assembly" below.
102- /// That statement needs a file, can't run via memory.
103- /// </summary>
104- static Assembly BuildAssembly ( string assemblyName )
105- {
106- var provider = CodeDomProvider . CreateProvider ( "CSharp" ) ;
107- var compilerparams = new CompilerParameters ( ) ;
108- var assemblies = from assembly in AppDomain . CurrentDomain . GetAssemblies ( )
109- where ! assembly . IsDynamic && ! string . IsNullOrEmpty ( assembly . Location )
110- select assembly . Location ;
111- compilerparams . ReferencedAssemblies . AddRange ( assemblies . ToArray ( ) ) ;
112-
113- compilerparams . GenerateExecutable = false ;
114- compilerparams . GenerateInMemory = false ;
115- compilerparams . IncludeDebugInformation = false ;
116- compilerparams . OutputAssembly = assemblyName ;
117-
118- var dir = Path . GetDirectoryName ( new StackTrace ( true ) . GetFrame ( 0 ) . GetFileName ( ) ) ;
119- string DomainCodePath = Path . Combine ( dir , "DomainCode.cs" ) ;
120- var results = provider . CompileAssemblyFromFile ( compilerparams , DomainCodePath ) ;
121- if ( results . Errors . HasErrors )
122- {
123- var errors = new System . Text . StringBuilder ( "Compiler Errors:\n " ) ;
124- foreach ( CompilerError error in results . Errors )
86+ try
87+ {
88+ var theProxy = ( Proxy ) domain . CreateInstanceAndUnwrap (
89+ type . Assembly . FullName ,
90+ type . FullName ) ;
91+ theProxy . Call ( "InitPython" , ShutdownMode . Reload ) ;
92+
93+ // handle refering a clr object created in previous domain,
94+ // it should had been deserialized and became callable agian.
95+ theProxy . Call ( "RunTestObject" , handle ) ;
96+ theProxy . Call ( "ShutdownPythonCompletely" ) ;
97+ }
98+ finally
12599 {
126- errors . AppendFormat ( "Line {0},{1}\t : {2}\n " ,
127- error . Line , error . Column , error . ErrorText ) ;
100+ AppDomain . Unload ( domain ) ;
128101 }
129- throw new Exception ( errors . ToString ( ) ) ;
130102 }
131- else
103+ if ( PythonEngine . DefaultShutdownMode == ShutdownMode . Normal )
132104 {
133- return results . CompiledAssembly ;
105+ Assert . IsTrue ( Runtime . Runtime . Py_IsInitialized ( ) == 0 ) ;
134106 }
135107 }
136108
@@ -246,7 +218,7 @@ public static void RunPython()
246218 AppDomain . CurrentDomain . DomainUnload += OnDomainUnload ;
247219 string name = AppDomain . CurrentDomain . FriendlyName ;
248220 Console . WriteLine ( string . Format ( "[{0} in .NET] In PythonRunner.RunPython" , name ) ) ;
249- PythonEngine . Initialize ( mode : ShutdownMode . Reload ) ;
221+ PythonEngine . Initialize ( ) ;
250222 using ( Py . GIL ( ) )
251223 {
252224 try
@@ -287,8 +259,21 @@ public static void ShutdownPython()
287259 public static void ShutdownPythonCompletely ( )
288260 {
289261 PythonEngine . EndAllowThreads ( _state ) ;
290- PythonEngine . ShutdownMode = ShutdownMode . Normal ;
262+ // XXX: Reload mode will reserve clr objects after `Runtime.Shutdown`,
263+ // if it used a another mode(the default mode) in other tests,
264+ // when other tests trying to access these reserved objects, it may cause Domain exception,
265+ // thus it needs to reduct to Soft mode to make sure all clr objects remove from Python.
266+ if ( PythonEngine . DefaultShutdownMode != ShutdownMode . Reload )
267+ {
268+ PythonEngine . ShutdownMode = ShutdownMode . Soft ;
269+ }
291270 PythonEngine . Shutdown ( ) ;
271+ if ( PythonEngine . DefaultShutdownMode == ShutdownMode . Normal )
272+ {
273+ // Normal mode will shutdown the VM, so it needs to be shutdown
274+ // for avoiding influence with other tests.
275+ Runtime . Runtime . Shutdown ( ) ;
276+ }
292277 }
293278
294279 public static IntPtr GetTestObject ( )
0 commit comments