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

Commit37df647

Browse files
committed
do not eat all exceptions when trying to add CLR reference, provide more info when CLR assemblies are failed to be loaded
1. When trying to implicitly load assemblies, and that fails NOT because an assembly is missing, but because loading failed for some reason, emit Python warning.2. When trying to import a module in our import hook, if the module name is an assembly name, and we fail to load it, and Python also fails to find a module with the same name, add the exceptions we got during the attempt to load it into __cause__ of the final ImportErrorBREAKING: clr.AddReference will now throw exceptions besides FileNotFoundException.Additional: a few uses of BorrowedReferenceThis addresses#261It is an alternative to#298
1 parent3e1fc2e commit37df647

11 files changed

+141
-113
lines changed

‎CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1111

1212
###Changed
1313
- Drop support for Python 2
14+
-`clr.AddReference` may now throw errors besides`FileNotFoundException`, that provide more
15+
details about the cause of the failure
16+
-`clr.AddReference` no longer adds ".dll" implicitly
17+
- the old`CLR` module prefix is gone
1418

1519
###Fixed
1620

‎src/embed_tests/pyimport.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public void SetUp()
3838
stringtestPath=Path.Combine(TestContext.CurrentContext.TestDirectory,s);
3939

4040
IntPtrstr=Runtime.Runtime.PyString_FromString(testPath);
41-
IntPtrpath=Runtime.Runtime.PySys_GetObject("path");
42-
Runtime.Runtime.PyList_Append(newBorrowedReference(path),str);
41+
BorrowedReferencepath=Runtime.Runtime.PySys_GetObject("path");
42+
Runtime.Runtime.PyList_Append(path,str);
4343
}
4444

4545
[TearDown]
@@ -83,5 +83,28 @@ public void TestCastGlobalVar()
8383
Assert.AreEqual("2",foo.FOO.ToString());
8484
Assert.AreEqual("2",foo.test_foo().ToString());
8585
}
86+
87+
[Test]
88+
publicvoidBadAssembly()
89+
{
90+
stringpath;
91+
if(Python.Runtime.Runtime.IsWindows)
92+
{
93+
path=@"C:\Windows\System32\kernel32.dll";
94+
}
95+
else
96+
{
97+
Assert.Pass("TODO: add bad assembly location for other platforms");
98+
return;
99+
}
100+
101+
stringcode=$@"
102+
import clr
103+
clr.AddReference('{path}')
104+
";
105+
106+
varerror=Assert.Throws<PythonException>(()=>PythonEngine.Exec(code));
107+
Assert.AreEqual(nameof(FileLoadException),error.PythonTypeName);
108+
}
86109
}
87110
}

‎src/runtime/assemblymanager.cs

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ private static Assembly ResolveHandler(object ob, ResolveEventArgs args)
137137
/// </summary>
138138
internalstaticvoidUpdatePath()
139139
{
140-
IntPtrlist=Runtime.PySys_GetObject("path");
140+
BorrowedReferencelist=Runtime.PySys_GetObject("path");
141141
varcount=Runtime.PyList_Size(list);
142142
if(count!=pypath.Count)
143143
{
@@ -199,19 +199,14 @@ public static string FindAssembly(string name)
199199
/// </summary>
200200
publicstaticAssemblyLoadAssembly(stringname)
201201
{
202-
Assemblyassembly=null;
203202
try
204203
{
205-
assembly=Assembly.Load(name);
204+
returnAssembly.Load(name);
206205
}
207-
catch(Exception)
206+
catch(FileNotFoundException)
208207
{
209-
//if (!(e is System.IO.FileNotFoundException))
210-
//{
211-
// throw;
212-
//}
208+
returnnull;
213209
}
214-
returnassembly;
215210
}
216211

217212

@@ -221,18 +216,8 @@ public static Assembly LoadAssembly(string name)
221216
publicstaticAssemblyLoadAssemblyPath(stringname)
222217
{
223218
stringpath=FindAssembly(name);
224-
Assemblyassembly=null;
225-
if(path!=null)
226-
{
227-
try
228-
{
229-
assembly=Assembly.LoadFrom(path);
230-
}
231-
catch(Exception)
232-
{
233-
}
234-
}
235-
returnassembly;
219+
if(path==null)returnnull;
220+
returnAssembly.LoadFrom(path);
236221
}
237222

238223
/// <summary>
@@ -242,25 +227,14 @@ public static Assembly LoadAssemblyPath(string name)
242227
/// <returns></returns>
243228
publicstaticAssemblyLoadAssemblyFullPath(stringname)
244229
{
245-
Assemblyassembly=null;
246230
if(Path.IsPathRooted(name))
247231
{
248-
if(!Path.HasExtension(name))
249-
{
250-
name=name+".dll";
251-
}
252232
if(File.Exists(name))
253233
{
254-
try
255-
{
256-
assembly=Assembly.LoadFrom(name);
257-
}
258-
catch(Exception)
259-
{
260-
}
234+
returnAssembly.LoadFrom(name);
261235
}
262236
}
263-
returnassembly;
237+
returnnull;
264238
}
265239

266240
/// <summary>
@@ -291,7 +265,7 @@ public static Assembly FindLoadedAssembly(string name)
291265
/// actually loads an assembly.
292266
/// Call ONLY for namespaces that HAVE NOT been cached yet.
293267
/// </remarks>
294-
publicstaticboolLoadImplicit(stringname,boolwarn=true)
268+
publicstaticboolLoadImplicit(stringname,Action<Exception>assemblyLoadErrorHandler,boolwarn=true)
295269
{
296270
string[]names=name.Split('.');
297271
varloaded=false;
@@ -308,14 +282,23 @@ public static bool LoadImplicit(string name, bool warn = true)
308282
assembliesSet=newHashSet<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
309283
}
310284
Assemblya=FindLoadedAssembly(s);
311-
if(a==null)
312-
{
313-
a=LoadAssemblyPath(s);
314-
}
315-
if(a==null)
285+
try
316286
{
317-
a=LoadAssembly(s);
287+
if(a==null)
288+
{
289+
a=LoadAssemblyPath(s);
290+
}
291+
292+
if(a==null)
293+
{
294+
a=LoadAssembly(s);
295+
}
318296
}
297+
catch(FileLoadExceptione){assemblyLoadErrorHandler(e);}
298+
catch(BadImageFormatExceptione){assemblyLoadErrorHandler(e);}
299+
catch(System.Security.SecurityExceptione){assemblyLoadErrorHandler(e);}
300+
catch(PathTooLongExceptione){assemblyLoadErrorHandler(e);}
301+
319302
if(a!=null&&!assembliesSet.Contains(a))
320303
{
321304
loaded=true;

‎src/runtime/exceptions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ public static void SetError(IntPtr ob, string value)
254254
/// Sets the current Python exception given a Python object.
255255
/// This is a wrapper for the Python PyErr_SetObject call.
256256
/// </remarks>
257-
publicstaticvoidSetError(IntPtrob,IntPtrvalue)
257+
publicstaticvoidSetError(IntPtrtype,IntPtrexceptionObject)
258258
{
259-
Runtime.PyErr_SetObject(ob,value);
259+
Runtime.PyErr_SetObject(newBorrowedReference(type),newBorrowedReference(exceptionObject));
260260
}
261261

262262
/// <summary>
@@ -286,7 +286,7 @@ public static void SetError(Exception e)
286286

287287
IntPtrop=CLRObject.GetInstHandle(e);
288288
IntPtretype=Runtime.PyObject_GetAttrString(op,"__class__");
289-
Runtime.PyErr_SetObject(etype,op);
289+
Runtime.PyErr_SetObject(newBorrowedReference(etype),newBorrowedReference(op));
290290
Runtime.XDecref(etype);
291291
Runtime.XDecref(op);
292292
}

‎src/runtime/importhook.cs

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

45
namespacePython.Runtime
@@ -222,22 +223,12 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
222223
// Check these BEFORE the built-in import runs; may as well
223224
// do the Incref()ed return here, since we've already found
224225
// the module.
225-
if(mod_name=="clr")
226+
if(mod_name=="clr"||mod_name=="CLR")
226227
{
227-
IntPtrclr_module=GetCLRModule(fromList);
228-
if(clr_module!=IntPtr.Zero)
228+
if(mod_name=="CLR")
229229
{
230-
IntPtrsys_modules=Runtime.PyImport_GetModuleDict();
231-
if(sys_modules!=IntPtr.Zero)
232-
{
233-
Runtime.PyDict_SetItemString(sys_modules,"clr",clr_module);
234-
}
230+
Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'.");
235231
}
236-
returnclr_module;
237-
}
238-
if(mod_name=="CLR")
239-
{
240-
Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'.");
241232
IntPtrclr_module=GetCLRModule(fromList);
242233
if(clr_module!=IntPtr.Zero)
243234
{
@@ -249,53 +240,45 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
249240
}
250241
returnclr_module;
251242
}
243+
252244
stringrealname=mod_name;
253245
stringclr_prefix=null;
254-
if(mod_name.StartsWith("CLR."))
255-
{
256-
clr_prefix="CLR.";// prepend when adding the module to sys.modules
257-
realname=mod_name.Substring(4);
258-
stringmsg=$"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly.";
259-
Exceptions.deprecation(msg);
260-
}
261-
else
246+
247+
// 2010-08-15: Always seemed smart to let python try first...
248+
// This shaves off a few tenths of a second on test_module.py
249+
// and works around a quirk where 'sys' is found by the
250+
// LoadImplicit() deprecation logic.
251+
// Turns out that the AssemblyManager.ResolveHandler() checks to see if any
252+
// Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
253+
// little sense to me.
254+
IntPtrres=Runtime.PyObject_Call(py_import,args,kw);
255+
if(res!=IntPtr.Zero)
262256
{
263-
// 2010-08-15: Always seemed smart to let python try first...
264-
// This shaves off a few tenths of a second on test_module.py
265-
// and works around a quirk where 'sys' is found by the
266-
// LoadImplicit() deprecation logic.
267-
// Turns out that the AssemblyManager.ResolveHandler() checks to see if any
268-
// Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
269-
// little sense to me.
270-
IntPtrres=Runtime.PyObject_Call(py_import,args,kw);
271-
if(res!=IntPtr.Zero)
272-
{
273-
// There was no error.
274-
if(fromlist&&IsLoadAll(fromList))
275-
{
276-
varmod=ManagedType.GetManagedObject(res)asModuleObject;
277-
mod?.LoadNames();
278-
}
279-
returnres;
280-
}
281-
// There was an error
282-
if(!Exceptions.ExceptionMatches(Exceptions.ImportError))
257+
// There was no error.
258+
if(fromlist&&IsLoadAll(fromList))
283259
{
284-
// and it was NOT an ImportError; bail out here.
285-
returnIntPtr.Zero;
260+
varmod=ManagedType.GetManagedObject(res)asModuleObject;
261+
mod?.LoadNames();
286262
}
263+
returnres;
264+
}
265+
// There was an error
266+
if(!Exceptions.ExceptionMatches(Exceptions.ImportError))
267+
{
268+
// and it was NOT an ImportError; bail out here.
269+
returnIntPtr.Zero;
270+
}
287271

288-
if(mod_name==string.Empty)
289-
{
290-
// Most likely a missing relative import.
291-
// For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
292-
// from . import _html5lib
293-
// We don't support them anyway
294-
returnIntPtr.Zero;
295-
}
296-
// Otherwise, just clear the it.
297-
Exceptions.Clear();
272+
if(mod_name==string.Empty)
273+
{
274+
// Most likely a missing relative import.
275+
// For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
276+
// from . import _html5lib
277+
// We don't support them anyway
278+
returnIntPtr.Zero;
298279
}
280+
// Otherwise, just clear the it.
281+
Exceptions.Clear();
299282

300283
string[]names=realname.Split('.');
301284

@@ -312,11 +295,22 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
312295
AssemblyManager.UpdatePath();
313296
if(!AssemblyManager.IsValidNamespace(realname))
314297
{
315-
if(!AssemblyManager.LoadImplicit(realname))
298+
varloadExceptions=newList<Exception>();
299+
if(!AssemblyManager.LoadImplicit(realname,assemblyLoadErrorHandler:loadExceptions.Add))
316300
{
317301
// May be called when a module being imported imports a module.
318302
// In particular, I've seen decimal import copy import org.python.core
319-
returnRuntime.PyObject_Call(py_import,args,kw);
303+
IntPtrimportResult=Runtime.PyObject_Call(py_import,args,kw);
304+
// TODO: use ModuleNotFoundError in Python 3.6+
305+
if(importResult==IntPtr.Zero&&loadExceptions.Count>0
306+
&&Exceptions.ExceptionMatches(Exceptions.ImportError))
307+
{
308+
loadExceptions.Add(newPythonException());
309+
varimportError=newPyObject(newBorrowedReference(Exceptions.ImportError));
310+
importError.SetAttr("__cause__",newAggregateException(loadExceptions).ToPython());
311+
Runtime.PyErr_SetObject(newBorrowedReference(Exceptions.ImportError),importError.Reference);
312+
}
313+
returnimportResult;
320314
}
321315
}
322316

‎src/runtime/methodbinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
291291
IntPtrvalueList=Runtime.PyDict_Values(kw);
292292
for(inti=0;i<pynkwargs;++i)
293293
{
294-
varkeyStr=Runtime.GetManagedString(Runtime.PyList_GetItem(keylist,i));
295-
kwargDict[keyStr]=Runtime.PyList_GetItem(valueList,i).DangerousGetAddress();
294+
varkeyStr=Runtime.GetManagedString(Runtime.PyList_GetItem(newBorrowedReference(keylist),i));
295+
kwargDict[keyStr]=Runtime.PyList_GetItem(newBorrowedReference(valueList),i).DangerousGetAddress();
296296
}
297297
Runtime.XDecref(keylist);
298298
Runtime.XDecref(valueList);

‎src/runtime/moduleobject.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public ManagedType GetAttribute(string name, bool guess)
119119
// cost. Ask the AssemblyManager to do implicit loading for each
120120
// of the steps in the qualified name, then try it again.
121121
boolignore=name.StartsWith("__");
122-
if(AssemblyManager.LoadImplicit(qname,!ignore))
122+
if(AssemblyManager.LoadImplicit(qname,assemblyLoadErrorHandler:ImportWarning,!ignore))
123123
{
124124
if(AssemblyManager.IsValidNamespace(qname))
125125
{
@@ -161,6 +161,11 @@ public ManagedType GetAttribute(string name, bool guess)
161161
returnnull;
162162
}
163163

164+
staticvoidImportWarning(Exceptionexception)
165+
{
166+
Exceptions.warn(exception.ToString(),Exceptions.ImportWarning);
167+
}
168+
164169

165170
/// <summary>
166171
/// Stores an attribute in the instance dict for future lookups.
@@ -365,7 +370,7 @@ internal void InitializePreload()
365370
if(interactive_preload)
366371
{
367372
interactive_preload=false;
368-
if(Runtime.PySys_GetObject("ps1")!=IntPtr.Zero)
373+
if(!Runtime.PySys_GetObject("ps1").IsNull)
369374
{
370375
preload=true;
371376
}

‎src/runtime/pylist.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public PyList(IntPtr ptr) : base(ptr)
2222
{
2323
}
2424

25+
/// <summary>
26+
/// Creates new <see cref="PyList"/> pointing to the same object, as the given reference.
27+
/// </summary>
28+
internalPyList(BorrowedReferencereference):base(reference){}
29+
2530

2631
/// <summary>
2732
/// PyList Constructor

‎src/runtime/pysequence.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ protected PySequence(IntPtr ptr) : base(ptr)
1616
{
1717
}
1818

19+
internalPySequence(BorrowedReferencereference):base(reference){}
20+
1921
protectedPySequence()
2022
{
2123
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp