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

Commit53836de

Browse files
committed
ShutdownMode has been removed. The only shutdown mode supported now is an equivalent ofShutdownMode.Reload
also in this change:- fixed Python derived types not being decrefed when an instance is deallocated- reduced time and amount of storage needed for runtime reload- removed circular reference loop between Type <-> ConstructorBinding(s)+ exposed Runtime.TryCollectingGarbage
1 parentdfeb354 commit53836de

30 files changed

+174
-357
lines changed

‎.github/workflows/main.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ jobs:
1414
os:[windows, ubuntu, macos]
1515
python:["3.6", "3.7", "3.8", "3.9", "3.10"]
1616
platform:[x64]
17-
shutdown_mode:[Normal, Soft]
18-
19-
env:
20-
PYTHONNET_SHUTDOWN_MODE:${{ matrix.SHUTDOWN_MODE }}
2117

2218
steps:
2319
-name:Set Environment on macOS

‎CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ Instead, `PyIterable` does that.
107107

108108
###Removed
109109

110+
-`ShutdownMode` has been removed. The only shutdown mode supported now is an equivalent of`ShutdownMode.Reload`.
111+
There is no need to specify it.
110112
- implicit assembly loading (you have to explicitly`clr.AddReference` before doing import)
111113
- messages in`PythonException` no longer start with exception type
112114
-`PyScopeManager`,`PyScopeException`,`PyScope` (use`PyModule` instead)

‎src/embed_tests/Codecs.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static void TupleConversionsGeneric<T, TTuple>()
3434
using(varscope=Py.CreateScope())
3535
{
3636
voidAccept(Tvalue)=>restored=value;
37-
varaccept=newAction<T>(Accept).ToPython();
37+
usingvaraccept=newAction<T>(Accept).ToPython();
3838
scope.Set(nameof(tuple),tuple);
3939
scope.Set(nameof(accept),accept);
4040
scope.Exec($"{nameof(accept)}({nameof(tuple)})");
@@ -55,7 +55,7 @@ static void TupleConversionsObject<T, TTuple>()
5555
using(varscope=Py.CreateScope())
5656
{
5757
voidAccept(objectvalue)=>restored=(T)value;
58-
varaccept=newAction<object>(Accept).ToPython();
58+
usingvaraccept=newAction<object>(Accept).ToPython();
5959
scope.Set(nameof(tuple),tuple);
6060
scope.Set(nameof(accept),accept);
6161
scope.Exec($"{nameof(accept)}({nameof(tuple)})");
@@ -71,7 +71,7 @@ public void TupleRoundtripObject()
7171
staticvoidTupleRoundtripObject<T,TTuple>()
7272
{
7373
vartuple=Activator.CreateInstance(typeof(T),42.0,"42",newobject());
74-
varpyTuple=TupleCodec<TTuple>.Instance.TryEncode(tuple);
74+
usingvarpyTuple=TupleCodec<TTuple>.Instance.TryEncode(tuple);
7575
Assert.IsTrue(TupleCodec<TTuple>.Instance.TryDecode(pyTuple,outobjectrestored));
7676
Assert.AreEqual(expected:tuple,actual:restored);
7777
}
@@ -85,7 +85,7 @@ public void TupleRoundtripGeneric()
8585
staticvoidTupleRoundtripGeneric<T,TTuple>()
8686
{
8787
vartuple=Activator.CreateInstance(typeof(T),42,"42",newobject());
88-
varpyTuple=TupleCodec<TTuple>.Instance.TryEncode(tuple);
88+
usingvarpyTuple=TupleCodec<TTuple>.Instance.TryEncode(tuple);
8989
Assert.IsTrue(TupleCodec<TTuple>.Instance.TryDecode(pyTuple,outTrestored));
9090
Assert.AreEqual(expected:tuple,actual:restored);
9191
}
@@ -98,9 +98,9 @@ public void ListDecoderTest()
9898
varcodec=ListDecoder.Instance;
9999
varitems=newList<PyObject>(){newPyInt(1),newPyInt(2),newPyInt(3)};
100100

101-
varpyList=newPyList(items.ToArray());
101+
usingvarpyList=newPyList(items.ToArray());
102102

103-
varpyListType=pyList.GetPythonType();
103+
usingvarpyListType=pyList.GetPythonType();
104104
Assert.IsTrue(codec.CanDecode(pyListType,typeof(IList<bool>)));
105105
Assert.IsTrue(codec.CanDecode(pyListType,typeof(IList<int>)));
106106
Assert.IsFalse(codec.CanDecode(pyListType,typeof(System.Collections.IEnumerable)));
@@ -128,8 +128,8 @@ public void ListDecoderTest()
128128
Assert.Throws(typeof(InvalidCastException),()=>{varx=stringList[0];});
129129

130130
//can't convert python iterable to list (this will require a copy which isn't lossless)
131-
varfoo=GetPythonIterable();
132-
varfooType=foo.GetPythonType();
131+
usingvarfoo=GetPythonIterable();
132+
usingvarfooType=foo.GetPythonType();
133133
Assert.IsFalse(codec.CanDecode(fooType,typeof(IList<int>)));
134134
}
135135

@@ -140,8 +140,8 @@ public void SequenceDecoderTest()
140140
varitems=newList<PyObject>(){newPyInt(1),newPyInt(2),newPyInt(3)};
141141

142142
//SequenceConverter can only convert to any ICollection
143-
varpyList=newPyList(items.ToArray());
144-
varlistType=pyList.GetPythonType();
143+
usingvarpyList=newPyList(items.ToArray());
144+
usingvarlistType=pyList.GetPythonType();
145145
//it can convert a PyList, since PyList satisfies the python sequence protocol
146146

147147
Assert.IsFalse(codec.CanDecode(listType,typeof(bool)));

‎src/embed_tests/TestCallbacks.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
usingPython.Runtime;
55

66
namespacePython.EmbeddingTest{
7-
usingRuntime=Python.Runtime.Runtime;
8-
97
publicclassTestCallbacks{
108
[OneTimeSetUp]
119
publicvoidSetUp(){
@@ -22,11 +20,13 @@ public void TestNoOverloadException() {
2220
intpassed=0;
2321
varaFunctionThatCallsIntoPython=newAction<int>(value=>passed=value);
2422
using(Py.GIL()){
25-
dynamiccallWith42=PythonEngine.Eval("lambda f: f([42])");
26-
varerror=Assert.Throws<PythonException>(()=>callWith42(aFunctionThatCallsIntoPython.ToPython()));
23+
usingdynamiccallWith42=PythonEngine.Eval("lambda f: f([42])");
24+
usingvarpyFunc=aFunctionThatCallsIntoPython.ToPython();
25+
varerror=Assert.Throws<PythonException>(()=>callWith42(pyFunc));
2726
Assert.AreEqual("TypeError",error.Type.Name);
2827
stringexpectedArgTypes="(<class 'list'>)";
2928
StringAssert.EndsWith(expectedArgTypes,error.Message);
29+
error.Traceback.Dispose();
3030
}
3131
}
3232
}

‎src/embed_tests/TestDomainReload.cs

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,6 @@ public static void DomainReloadAndGC()
6767
RunAssemblyAndUnload("test2");
6868
Assert.That(PyRuntime.Py_IsInitialized()!=0,
6969
"On soft-shutdown mode, Python runtime should still running");
70-
71-
if(PythonEngine.DefaultShutdownMode==ShutdownMode.Normal)
72-
{
73-
// The default mode is a normal mode,
74-
// it should shutdown the Python VM avoiding influence other tests.
75-
PyRuntime.PyGILState_Ensure();
76-
PyRuntime.Py_Finalize();
77-
}
7870
}
7971

8072
#region CrossDomainObject
@@ -222,7 +214,7 @@ static void RunAssemblyAndUnload(string domainName)
222214
// assembly (and Python .NET) to reside
223215
vartheProxy=CreateInstanceInstanceAndUnwrap<Proxy>(domain);
224216

225-
theProxy.Call(nameof(PythonRunner.InitPython),ShutdownMode.Soft,PyRuntime.PythonDLL);
217+
theProxy.Call(nameof(PythonRunner.InitPython),PyRuntime.PythonDLL);
226218
// From now on use the Proxy to call into the new assembly
227219
theProxy.RunPython();
228220

@@ -290,7 +282,7 @@ static void RunDomainReloadSteps<T1, T2>() where T1 : CrossCaller where T2 : Cro
290282
try
291283
{
292284
vartheProxy=CreateInstanceInstanceAndUnwrap<Proxy>(domain);
293-
theProxy.Call(nameof(PythonRunner.InitPython),ShutdownMode.Reload,PyRuntime.PythonDLL);
285+
theProxy.Call(nameof(PythonRunner.InitPython),PyRuntime.PythonDLL);
294286

295287
varcaller=CreateInstanceInstanceAndUnwrap<T1>(domain);
296288
arg=caller.Execute(arg);
@@ -308,7 +300,7 @@ static void RunDomainReloadSteps<T1, T2>() where T1 : CrossCaller where T2 : Cro
308300
try
309301
{
310302
vartheProxy=CreateInstanceInstanceAndUnwrap<Proxy>(domain);
311-
theProxy.Call(nameof(PythonRunner.InitPython),ShutdownMode.Reload,PyRuntime.PythonDLL);
303+
theProxy.Call(nameof(PythonRunner.InitPython),PyRuntime.PythonDLL);
312304

313305
varcaller=CreateInstanceInstanceAndUnwrap<T2>(domain);
314306
caller.Execute(arg);
@@ -319,10 +311,8 @@ static void RunDomainReloadSteps<T1, T2>() where T1 : CrossCaller where T2 : Cro
319311
AppDomain.Unload(domain);
320312
}
321313
}
322-
if(PythonEngine.DefaultShutdownMode==ShutdownMode.Normal)
323-
{
324-
Assert.IsTrue(PyRuntime.Py_IsInitialized()==0);
325-
}
314+
315+
Assert.IsTrue(PyRuntime.Py_IsInitialized()!=0);
326316
}
327317
}
328318

@@ -368,10 +358,10 @@ public static void RunPython()
368358

369359
privatestaticIntPtr_state;
370360

371-
publicstaticvoidInitPython(ShutdownModemode,stringdllName)
361+
publicstaticvoidInitPython(stringdllName)
372362
{
373363
PyRuntime.PythonDLL=dllName;
374-
PythonEngine.Initialize(mode:mode);
364+
PythonEngine.Initialize();
375365
_state=PythonEngine.BeginAllowThreads();
376366
}
377367

@@ -384,15 +374,7 @@ public static void ShutdownPython()
384374
publicstaticvoidShutdownPythonCompletely()
385375
{
386376
PythonEngine.EndAllowThreads(_state);
387-
// XXX: Reload mode will reserve clr objects after `Runtime.Shutdown`,
388-
// if it used a another mode(the default mode) in other tests,
389-
// when other tests trying to access these reserved objects, it may cause Domain exception,
390-
// thus it needs to reduct to Soft mode to make sure all clr objects remove from Python.
391-
vardefaultMode=PythonEngine.DefaultShutdownMode;
392-
if(defaultMode!=ShutdownMode.Reload)
393-
{
394-
PythonEngine.ShutdownMode=defaultMode;
395-
}
377+
396378
PythonEngine.Shutdown();
397379
}
398380

‎src/embed_tests/pyinitialize.cs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -151,51 +151,6 @@ public void ShutdownHandlers()
151151
// Wrong: (4 * 2) + 1 + 1 + 1 = 11
152152
Assert.That(shutdown_count,Is.EqualTo(12));
153153
}
154-
155-
[Test]
156-
publicstaticvoidTestRunExitFuncs()
157-
{
158-
if(Runtime.Runtime.GetDefaultShutdownMode()==ShutdownMode.Normal)
159-
{
160-
// If the runtime using the normal mode,
161-
// callback registered by atexit will be called after we release the clr information,
162-
// thus there's no chance we can check it here.
163-
Assert.Ignore("Skip on normal mode");
164-
}
165-
Runtime.Runtime.Initialize();
166-
PyObjectatexit;
167-
try
168-
{
169-
atexit=Py.Import("atexit");
170-
}
171-
catch(PythonExceptione)
172-
{
173-
stringmsg=e.ToString();
174-
boolisImportError=e.Is(Exceptions.ImportError);
175-
Runtime.Runtime.Shutdown();
176-
177-
if(isImportError)
178-
{
179-
Assert.Ignore("no atexit module");
180-
}
181-
else
182-
{
183-
Assert.Fail(msg);
184-
}
185-
PythonEngine.InteropConfiguration=InteropConfiguration.MakeDefault();
186-
return;
187-
}
188-
boolcalled=false;
189-
Actioncallback=()=>
190-
{
191-
called=true;
192-
};
193-
atexit.InvokeMethod("register",callback.ToPython()).Dispose();
194-
atexit.Dispose();
195-
Runtime.Runtime.Shutdown();
196-
Assert.True(called);
197-
PythonEngine.InteropConfiguration=InteropConfiguration.MakeDefault();
198-
}
199154
}
200155

201156
publicclassImportClassShutdownRefcountClass{}

‎src/runtime/ReflectedClrType.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
usingSystem;
2+
usingSystem.Collections.Generic;
23
usingSystem.Diagnostics;
34
usingSystem.Runtime.Serialization;
45

@@ -49,9 +50,9 @@ public static ReflectedClrType GetOrCreate(Type type)
4950
returnpyType;
5051
}
5152

52-
internalvoidRestore(InterDomainContextcontext)
53+
internalvoidRestore(Dictionary<string,object?>context)
5354
{
54-
varcb=context.Storage.GetValue<ClassBase>("impl");
55+
varcb=(ClassBase)context["impl"]!;
5556

5657
Debug.Assert(cbis notnull);
5758

‎src/runtime/StateSerialization/ClassManagerState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ namespace Python.Runtime.StateSerialization;
1010
[Serializable]
1111
internalclassClassManagerState
1212
{
13-
publicDictionary<ReflectedClrType,InterDomainContext>Contexts{get;set;}
13+
publicDictionary<ReflectedClrType,Dictionary<string,object?>>Contexts{get;set;}
1414
publicDictionary<MaybeType,ReflectedClrType>Cache{get;set;}
1515
}

‎src/runtime/StateSerialization/ICLRObjectStorer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ namespace Python.Runtime;
44

55
publicinterfaceICLRObjectStorer
66
{
7-
ICollection<CLRMappedItem>Store(CLRWrapperCollectionwrappers,RuntimeDataStoragestorage);
8-
CLRWrapperCollectionRestore(RuntimeDataStoragestorage);
7+
ICollection<CLRMappedItem>Store(CLRWrapperCollectionwrappers,Dictionary<string,object?>storage);
8+
CLRWrapperCollectionRestore(Dictionary<string,object?>storage);
99
}

‎src/runtime/StateSerialization/SharedObjectsState.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ internal class SharedObjectsState
1212
{
1313
publicDictionary<PyObject,CLRObject>InternalStores{get;init;}
1414
publicDictionary<PyObject,ExtensionType>Extensions{get;init;}
15-
publicRuntimeDataStorageWrappers{get;init;}
16-
publicDictionary<PyObject,InterDomainContext>Contexts{get;init;}
15+
publicDictionary<string,object?>Wrappers{get;init;}
16+
publicDictionary<PyObject,Dictionary<string,object?>>Contexts{get;init;}
1717
}

‎src/runtime/Util.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal static class Util
1313
internalconststringUnstableApiMessage=
1414
"This API is unstable, and might be changed or removed in the next minor release";
1515
internalconststringMinimalPythonVersionRequired=
16-
"Only Python 3.5 or newer is supported";
16+
"Only Python 3.6 or newer is supported";
1717
internalconststringInternalUseOnly=
1818
"This API is for internal use only";
1919

‎src/runtime/classbase.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,17 @@ public static void tp_dealloc(NewReference lastRef)
341341

342342
CallClear(lastRef.Borrow());
343343

344-
IntPtraddr=lastRef.DangerousGetAddress();
345-
booldeleted=CLRObject.reflectedObjects.Remove(addr);
346-
Debug.Assert(deleted);
347-
348344
DecrefTypeAndFree(lastRef.Steal());
349345
}
350346

351347
publicstaticinttp_clear(BorrowedReferenceob)
352348
{
353-
TryFreeGCHandle(ob);
349+
if(TryFreeGCHandle(ob))
350+
{
351+
IntPtraddr=ob.DangerousGetAddress();
352+
booldeleted=CLRObject.reflectedObjects.Remove(addr);
353+
Debug.Assert(deleted);
354+
}
354355

355356
intbaseClearResult=BaseUnmanagedClear(ob);
356357
if(baseClearResult!=0)
@@ -390,13 +391,14 @@ internal static unsafe int BaseUnmanagedClear(BorrowedReference ob)
390391
returnclear(ob);
391392
}
392393

393-
protectedoverridevoidOnSave(BorrowedReferenceob,InterDomainContextcontext)
394+
protectedoverrideDictionary<string,object?>OnSave(BorrowedReferenceob)
394395
{
395-
base.OnSave(ob,context);
396-
context.Storage.AddValue("impl",this);
396+
varcontext=base.OnSave(ob)??new();
397+
context["impl"]=this;
398+
returncontext;
397399
}
398400

399-
protectedoverridevoidOnLoad(BorrowedReferenceob,InterDomainContext?context)
401+
protectedoverridevoidOnLoad(BorrowedReferenceob,Dictionary<string,object?>?context)
400402
{
401403
base.OnLoad(ob,context);
402404
vargcHandle=GCHandle.Alloc(this);

‎src/runtime/classderived.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -867,17 +867,19 @@ public static void PyFinalize(IPythonDerivedType obj)
867867

868868
internalstaticvoidFinalize(IntPtrderived)
869869
{
870-
booldeleted=CLRObject.reflectedObjects.Remove(derived);
871-
Debug.Assert(deleted);
872-
873870
var@ref=NewReference.DangerousFromPointer(derived);
874871

875872
ClassBase.tp_clear(@ref.Borrow());
876873

874+
vartype=Runtime.PyObject_TYPE(@ref.Borrow());
875+
877876
// rare case when it's needed
878877
// matches correspdonging PyObject_GC_UnTrack
879878
// in ClassDerivedObject.tp_dealloc
880879
Runtime.PyObject_GC_Del(@ref.Steal());
880+
881+
// must decref our type
882+
Runtime.XDecref(StolenReference.DangerousFromPointer(type.DangerousGetAddress()));
881883
}
882884

883885
internalstaticFieldInfo?GetPyObjField(Typetype)=>type.GetField(PyObjName,PyObjFlags);

‎src/runtime/classmanager.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,15 @@ internal static void RemoveClasses()
6565

6666
internalstaticClassManagerStateSaveRuntimeData()
6767
{
68-
varcontexts=newDictionary<ReflectedClrType,InterDomainContext>();
68+
varcontexts=newDictionary<ReflectedClrType,Dictionary<string,object?>>();
6969
foreach(varclsincache)
7070
{
71-
varcontext=contexts[cls.Value]=newInterDomainContext();
7271
varcb=(ClassBase)ManagedType.GetManagedObject(cls.Value)!;
73-
cb.Save(cls.Value,context);
72+
varcontext=cb.Save(cls.Value);
73+
if(contextis notnull)
74+
{
75+
contexts[cls.Value]=context;
76+
}
7477

7578
// Remove all members added in InitBaseClass.
7679
// this is done so that if domain reloads and a member of a
@@ -201,7 +204,7 @@ internal static ClassBase CreateClass(Type type)
201204
returnimpl;
202205
}
203206

204-
internalstaticvoidInitClassBase(Typetype,ClassBaseimpl,PyTypepyType)
207+
internalstaticvoidInitClassBase(Typetype,ClassBaseimpl,ReflectedClrTypepyType)
205208
{
206209
// First, we introspect the managed type and build some class
207210
// information, including generating the member descriptors

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp