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

Commit8a3647d

Browse files
committed
enabled decoding instanceless exceptions
Added new class clr.interop.PyErr with optional type, value, and traceback attributes. User can register decoders for it, that would let them decode instanceless (and even typeless) Python exceptions.These decoders will be invoked before the regular exception instance decoders.
1 parentee0ab7f commit8a3647d

File tree

7 files changed

+159
-8
lines changed

7 files changed

+159
-8
lines changed

‎src/embed_tests/Codecs.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ from datetime import datetime
371371
scope.Exec("Codecs.AcceptsDateTime(datetime(2021, 1, 22))");
372372
}
373373

374+
[Test]
375+
publicvoidExceptionDecodedNoInstance()
376+
{
377+
PyObjectConversions.RegisterDecoder(newInstancelessExceptionDecoder());
378+
usingvar_=Py.GIL();
379+
usingvarscope=Py.CreateScope();
380+
varerror=Assert.Throws<ValueErrorWrapper>(()=>PythonEngine.Exec(
381+
$"[].__iter__().__next__()"));
382+
Assert.AreEqual(TestExceptionMessage,error.Message);
383+
}
384+
374385
publicstaticvoidAcceptsDateTime(DateTimev){}
375386

376387
classValueErrorWrapper:Exception
@@ -381,7 +392,8 @@ public ValueErrorWrapper(string message) : base(message) { }
381392
classValueErrorCodec:IPyObjectEncoder,IPyObjectDecoder
382393
{
383394
publicboolCanDecode(PyObjectobjectType,TypetargetType)
384-
=>this.CanEncode(targetType)&&objectType.Equals(PythonEngine.Eval("ValueError"));
395+
=>this.CanEncode(targetType)
396+
&&PythonReferenceComparer.Instance.Equals(objectType,PythonEngine.Eval("ValueError"));
385397

386398
publicboolCanEncode(Typetype)=>type==typeof(ValueErrorWrapper)
387399
||typeof(ValueErrorWrapper).IsSubclassOf(type);
@@ -399,6 +411,26 @@ public PyObject TryEncode(object value)
399411
returnPythonEngine.Eval("ValueError").Invoke(error.Message.ToPython());
400412
}
401413
}
414+
415+
classInstancelessExceptionDecoder:IPyObjectDecoder
416+
{
417+
readonlyPyObjectPyErr=Py.Import("clr.interop").GetAttr("PyErr");
418+
419+
publicboolCanDecode(PyObjectobjectType,TypetargetType)
420+
=>PythonReferenceComparer.Instance.Equals(PyErr,objectType);
421+
422+
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
423+
{
424+
if(pyObj.HasAttr("value"))
425+
{
426+
value=default;
427+
returnfalse;
428+
}
429+
430+
value=(T)(object)newValueErrorWrapper(TestExceptionMessage);
431+
returntrue;
432+
}
433+
}
402434
}
403435

404436
/// <summary>

‎src/runtime/Python.Runtime.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
<EmbeddedResourceInclude="resources\clr.py">
4444
<LogicalName>clr.py</LogicalName>
4545
</EmbeddedResource>
46+
<EmbeddedResourceInclude="resources\interop.py">
47+
<LogicalName>interop.py</LogicalName>
48+
</EmbeddedResource>
4649
</ItemGroup>
4750

4851
<ItemGroup>

‎src/runtime/Util.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
#nullable enable
12
usingSystem;
3+
usingSystem.IO;
24
usingSystem.Runtime.InteropServices;
35

46
namespacePython.Runtime
@@ -41,5 +43,27 @@ internal static void WriteCLong(IntPtr type, int offset, Int64 flags)
4143
/// </summary>
4244
internalstaticIntPtrCoalesce(thisIntPtrprimary,IntPtrfallback)
4345
=>primary==IntPtr.Zero?fallback:primary;
46+
47+
/// <summary>
48+
/// Gets substring after last occurrence of <paramref name="symbol"/>
49+
/// </summary>
50+
internalstaticstring?AfterLast(thisstringstr,charsymbol)
51+
{
52+
if(strisnull)
53+
thrownewArgumentNullException(nameof(str));
54+
55+
intlast=str.LastIndexOf(symbol);
56+
returnlast>=0?str.Substring(last+1):null;
57+
}
58+
59+
internalstaticstringReadStringResource(thisSystem.Reflection.Assemblyassembly,stringresourceName)
60+
{
61+
if(assemblyisnull)thrownewArgumentNullException(nameof(assembly));
62+
if(string.IsNullOrEmpty(resourceName))thrownewArgumentNullException(nameof(resourceName));
63+
64+
usingvarstream=assembly.GetManifestResourceStream(resourceName);
65+
usingvarreader=newStreamReader(stream);
66+
returnreader.ReadToEnd();
67+
}
4468
}
4569
}

‎src/runtime/pythonengine.cs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
usingSystem;
22
usingSystem.Collections.Generic;
3+
usingSystem.Diagnostics;
34
usingSystem.IO;
45
usingSystem.Linq;
56
usingSystem.Reflection;
@@ -229,13 +230,11 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true,
229230
Runtime.PyDict_SetItemString(module_globals,"__builtins__",builtins);
230231

231232
Assemblyassembly=Assembly.GetExecutingAssembly();
232-
using(Streamstream=assembly.GetManifestResourceStream("clr.py"))
233-
using(varreader=newStreamReader(stream))
234-
{
235-
// add the contents of clr.py to the module
236-
stringclr_py=reader.ReadToEnd();
237-
Exec(clr_py,module_globals,locals.Reference);
238-
}
233+
// add the contents of clr.py to the module
234+
stringclr_py=assembly.ReadStringResource("clr.py");
235+
Exec(clr_py,module_globals,locals.Reference);
236+
237+
LoadSubmodule(module_globals,"clr.interop","interop.py");
239238

240239
// add the imported module to the clr module, and copy the API functions
241240
// and decorators into the main clr module.
@@ -258,6 +257,30 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true,
258257
}
259258
}
260259

260+
staticBorrowedReferenceDefineModule(stringname)
261+
{
262+
varmodule=Runtime.PyImport_AddModule(name);
263+
varmodule_globals=Runtime.PyModule_GetDict(module);
264+
varbuiltins=Runtime.PyEval_GetBuiltins();
265+
Runtime.PyDict_SetItemString(module_globals,"__builtins__",builtins);
266+
returnmodule;
267+
}
268+
269+
staticvoidLoadSubmodule(BorrowedReferencetargetModuleDict,stringfullName,stringresourceName)
270+
{
271+
stringmemberName=fullName.AfterLast('.');
272+
Debug.Assert(memberName!=null);
273+
274+
varmodule=DefineModule(fullName);
275+
varmodule_globals=Runtime.PyModule_GetDict(module);
276+
277+
Assemblyassembly=Assembly.GetExecutingAssembly();
278+
stringpyCode=assembly.ReadStringResource(resourceName);
279+
Exec(pyCode,module_globals.DangerousGetAddress(),module_globals.DangerousGetAddress());
280+
281+
Runtime.PyDict_SetItemString(targetModuleDict,memberName,module);
282+
}
283+
261284
staticvoidOnDomainUnload(object_,EventArgs__)
262285
{
263286
Shutdown();

‎src/runtime/pythonexception.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public PythonException(PyType type, PyObject? value, PyObject? traceback)
3737
/// </summary>
3838
internalstaticExceptionThrowLastAsClrException()
3939
{
40+
// prevent potential interop errors in this method
41+
// from crashing process with undebuggable StackOverflowException
42+
RuntimeHelpers.EnsureSufficientExecutionStack();
43+
4044
varexception=FetchCurrentOrNull(outExceptionDispatchInfo?dispatchInfo)
4145
??thrownewInvalidOperationException("No exception is set");
4246
dispatchInfo?.Throw();
@@ -83,6 +87,24 @@ internal static PythonException FetchCurrentRaw()
8387
returnnull;
8488
}
8589

90+
try
91+
{
92+
if(TryDecodePyErr(type,value,traceback)is{}pyErr)
93+
{
94+
type.Dispose();
95+
value.Dispose();
96+
traceback.Dispose();
97+
returnpyErr;
98+
}
99+
}
100+
catch
101+
{
102+
type.Dispose();
103+
value.Dispose();
104+
traceback.Dispose();
105+
throw;
106+
}
107+
86108
Runtime.PyErr_NormalizeException(type:reftype,val:refvalue,tb:reftraceback);
87109

88110
try
@@ -153,6 +175,11 @@ private static Exception FromPyErr(BorrowedReference typeRef, BorrowedReference
153175
returne;
154176
}
155177

178+
if(TryDecodePyErr(typeRef,valRef,tbRef)is{}pyErr)
179+
{
180+
returnpyErr;
181+
}
182+
156183
if(PyObjectConversions.TryDecode(valRef,typeRef,typeof(Exception),outobjectdecoded)
157184
&&decodedisExceptiondecodedException)
158185
{
@@ -164,6 +191,28 @@ private static Exception FromPyErr(BorrowedReference typeRef, BorrowedReference
164191
returnnewPythonException(type,value,traceback,inner);
165192
}
166193

194+
privatestaticException?TryDecodePyErr(BorrowedReferencetypeRef,BorrowedReferencevalRef,BorrowedReferencetbRef)
195+
{
196+
usingvartype=PyType.FromReference(typeRef);
197+
usingvarvalue=PyObject.FromNullableReference(valRef);
198+
usingvartraceback=PyObject.FromNullableReference(tbRef);
199+
200+
usingvarerrorDict=newPyDict();
201+
if(typeRef!=null)errorDict["type"]=type;
202+
if(valRef!=null)errorDict["value"]=value;
203+
if(tbRef!=null)errorDict["traceback"]=traceback;
204+
205+
usingvarpyErrType=Runtime.InteropModule.GetAttr("PyErr");
206+
usingvarpyErrInfo=pyErrType.Invoke(newPyTuple(),errorDict);
207+
if(PyObjectConversions.TryDecode(pyErrInfo.Reference,pyErrType.Reference,
208+
typeof(Exception),outobjectdecoded)&&decodedisExceptiondecodedPyErrInfo)
209+
{
210+
returndecodedPyErrInfo;
211+
}
212+
213+
returnnull;
214+
}
215+
167216
privatestaticException?FromCause(BorrowedReferencecause)
168217
{
169218
if(cause==null||cause.IsNone())returnnull;

‎src/runtime/resources/interop.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
_UNSET=object()
2+
3+
classPyErr:
4+
def__init__(self,type=_UNSET,value=_UNSET,traceback=_UNSET):
5+
ifnot(typeis_UNSET):
6+
self.type=type
7+
ifnot(valueis_UNSET):
8+
self.value=value
9+
ifnot(tracebackis_UNSET):
10+
self.traceback=traceback

‎src/runtime/runtime.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ internal static void Initialize(bool initSigs = false, ShutdownMode mode = Shutd
178178
}
179179
XDecref(item);
180180
AssemblyManager.UpdatePath();
181+
182+
clrInterop=GetModuleLazy("clr.interop");
181183
}
182184

183185
privatestaticvoidInitPyMembers()
@@ -406,6 +408,11 @@ internal static void Shutdown()
406408
Shutdown(mode);
407409
}
408410

411+
privatestaticLazy<PyObject>GetModuleLazy(stringmoduleName)
412+
=>moduleNameisnull
413+
?thrownewArgumentNullException(nameof(moduleName))
414+
:newLazy<PyObject>(()=>PyModule.Import(moduleName),isThreadSafe:false);
415+
409416
internalstaticShutdownModeGetDefaultShutdownMode()
410417
{
411418
stringmodeEvn=Environment.GetEnvironmentVariable("PYTHONNET_SHUTDOWN_MODE");
@@ -574,6 +581,9 @@ private static void MoveClrInstancesOnwershipToPython()
574581
internalstaticIntPtrPyNone;
575582
internalstaticIntPtrError;
576583

584+
privatestaticLazy<PyObject>clrInterop;
585+
internalstaticPyObjectInteropModule=>clrInterop.Value;
586+
577587
internalstaticBorrowedReferenceCLRMetaType=>newBorrowedReference(PyCLRMetaType);
578588

579589
publicstaticPyObjectNone

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp