| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3e1fc2e commit 5b989cb
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,6 +11,9 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 11 | 11 | ||
| 12 | 12 | ### Changed | |
| 13 | 13 | - 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 | ||
| 14 | 17 | ||
| 15 | 18 | ### Fixed | |
| 16 | 19 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,8 +38,8 @@ public void SetUp() | |||
| 38 | 38 | string testPath = Path.Combine(TestContext.CurrentContext.TestDirectory, s); | |
| 39 | 39 | ||
| 40 | 40 | IntPtr str = Runtime.Runtime.PyString_FromString(testPath); | |
| 41 | - IntPtr path = Runtime.Runtime.PySys_GetObject("path"); | ||
| 42 | - Runtime.Runtime.PyList_Append(new BorrowedReference(path), str); | ||
| 41 | + BorrowedReference path = Runtime.Runtime.PySys_GetObject("path"); | ||
| 42 | + Runtime.Runtime.PyList_Append(path, str); | ||
| 43 | 43 | } | |
| 44 | 44 | ||
| 45 | 45 | [TearDown] | |
@@ -83,5 +83,28 @@ public void TestCastGlobalVar() | |||
| 83 | 83 | Assert.AreEqual("2", foo.FOO.ToString()); | |
| 84 | 84 | Assert.AreEqual("2", foo.test_foo().ToString()); | |
| 85 | 85 | } | |
| 86 | + | ||
| 87 | + [Test] | ||
| 88 | + public void BadAssembly() | ||
| 89 | + { | ||
| 90 | + string path; | ||
| 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 | + string code = $@" | ||
| 102 | + import clr | ||
| 103 | + clr.AddReference('{path}') | ||
| 104 | + "; | ||
| 105 | + | ||
| 106 | + var error = Assert.Throws<PythonException>(() => PythonEngine.Exec(code)); | ||
| 107 | + Assert.AreEqual(nameof(FileLoadException), error.PythonTypeName); | ||
| 108 | + } | ||
| 86 | 109 | } | |
| 87 | 110 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -137,7 +137,7 @@ private static Assembly ResolveHandler(object ob, ResolveEventArgs args) | |||
| 137 | 137 | /// </summary> | |
| 138 | 138 | internal static void UpdatePath() | |
| 139 | 139 | { | |
| 140 | - IntPtr list = Runtime.PySys_GetObject("path"); | ||
| 140 | + BorrowedReference list = Runtime.PySys_GetObject("path"); | ||
| 141 | 141 | var count = Runtime.PyList_Size(list); | |
| 142 | 142 | if (count != pypath.Count) | |
| 143 | 143 | { | |
@@ -199,19 +199,14 @@ public static string FindAssembly(string name) | |||
| 199 | 199 | /// </summary> | |
| 200 | 200 | public static Assembly LoadAssembly(string name) | |
| 201 | 201 | { | |
| 202 | - Assembly assembly = null; | ||
| 203 | 202 | try | |
| 204 | 203 | { | |
| 205 | - assembly = Assembly.Load(name); | ||
| 204 | + return Assembly.Load(name); | ||
| 206 | 205 | } | |
| 207 | - catch (Exception) | ||
| 206 | + catch (FileNotFoundException) | ||
| 208 | 207 | { | |
| 209 | - //if (!(e is System.IO.FileNotFoundException)) | ||
| 210 | - //{ | ||
| 211 | - // throw; | ||
| 212 | - //} | ||
| 208 | + return null; | ||
| 213 | 209 | } | |
| 214 | - return assembly; | ||
| 215 | 210 | } | |
| 216 | 211 | ||
| 217 | 212 | ||
@@ -221,18 +216,8 @@ public static Assembly LoadAssembly(string name) | |||
| 221 | 216 | public static Assembly LoadAssemblyPath(string name) | |
| 222 | 217 | { | |
| 223 | 218 | string path = FindAssembly(name); | |
| 224 | - Assembly assembly = null; | ||
| 225 | - if (path != null) | ||
| 226 | - { | ||
| 227 | - try | ||
| 228 | - { | ||
| 229 | - assembly = Assembly.LoadFrom(path); | ||
| 230 | - } | ||
| 231 | - catch (Exception) | ||
| 232 | - { | ||
| 233 | - } | ||
| 234 | - } | ||
| 235 | - return assembly; | ||
| 219 | + if (path == null) return null; | ||
| 220 | + return Assembly.LoadFrom(path); | ||
| 236 | 221 | } | |
| 237 | 222 | ||
| 238 | 223 | /// <summary> | |
@@ -242,25 +227,14 @@ public static Assembly LoadAssemblyPath(string name) | |||
| 242 | 227 | /// <returns></returns> | |
| 243 | 228 | public static Assembly LoadAssemblyFullPath(string name) | |
| 244 | 229 | { | |
| 245 | - Assembly assembly = null; | ||
| 246 | 230 | if (Path.IsPathRooted(name)) | |
| 247 | 231 | { | |
| 248 | - if (!Path.HasExtension(name)) | ||
| 249 | - { | ||
| 250 | - name = name + ".dll"; | ||
| 251 | - } | ||
| 252 | 232 | if (File.Exists(name)) | |
| 253 | 233 | { | |
| 254 | - try | ||
| 255 | - { | ||
| 256 | - assembly = Assembly.LoadFrom(name); | ||
| 257 | - } | ||
| 258 | - catch (Exception) | ||
| 259 | - { | ||
| 260 | - } | ||
| 234 | + return Assembly.LoadFrom(name); | ||
| 261 | 235 | } | |
| 262 | 236 | } | |
| 263 | - return assembly; | ||
| 237 | + return null; | ||
| 264 | 238 | } | |
| 265 | 239 | ||
| 266 | 240 | /// <summary> | |
@@ -291,7 +265,7 @@ public static Assembly FindLoadedAssembly(string name) | |||
| 291 | 265 | /// actually loads an assembly. | |
| 292 | 266 | /// Call ONLY for namespaces that HAVE NOT been cached yet. | |
| 293 | 267 | /// </remarks> | |
| 294 | - public static bool LoadImplicit(string name, bool warn = true) | ||
| 268 | + public static bool LoadImplicit(string name, Action<Exception> assemblyLoadErrorHandler, bool warn = true) | ||
| 295 | 269 | { | |
| 296 | 270 | string[] names = name.Split('.'); | |
| 297 | 271 | var loaded = false; | |
@@ -308,14 +282,23 @@ public static bool LoadImplicit(string name, bool warn = true) | |||
| 308 | 282 | assembliesSet = new HashSet<Assembly>(AppDomain.CurrentDomain.GetAssemblies()); | |
| 309 | 283 | } | |
| 310 | 284 | Assembly a = FindLoadedAssembly(s); | |
| 311 | - if (a == null) | ||
| 312 | - { | ||
| 313 | - a = LoadAssemblyPath(s); | ||
| 314 | - } | ||
| 315 | - if (a == null) | ||
| 285 | + try | ||
| 316 | 286 | { | |
| 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 | + } | ||
| 318 | 296 | } | |
| 297 | + catch (FileLoadException e) { assemblyLoadErrorHandler(e); } | ||
| 298 | + catch (BadImageFormatException e) { assemblyLoadErrorHandler(e); } | ||
| 299 | + catch (System.Security.SecurityException e) { assemblyLoadErrorHandler(e); } | ||
| 300 | + catch (PathTooLongException e) { assemblyLoadErrorHandler(e); } | ||
| 301 | + | ||
| 319 | 302 | if (a != null && !assembliesSet.Contains(a)) | |
| 320 | 303 | { | |
| 321 | 304 | loaded = true; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -254,9 +254,9 @@ public static void SetError(IntPtr ob, string value) | |||
| 254 | 254 | /// Sets the current Python exception given a Python object. | |
| 255 | 255 | /// This is a wrapper for the Python PyErr_SetObject call. | |
| 256 | 256 | /// </remarks> | |
| 257 | - public static void SetError(IntPtr ob, IntPtr value) | ||
| 257 | + public static void SetError(IntPtr type, IntPtr exceptionObject) | ||
| 258 | 258 | { | |
| 259 | - Runtime.PyErr_SetObject(ob, value); | ||
| 259 | + Runtime.PyErr_SetObject(new BorrowedReference(type), new BorrowedReference(exceptionObject)); | ||
| 260 | 260 | } | |
| 261 | 261 | ||
| 262 | 262 | /// <summary> | |
@@ -286,7 +286,7 @@ public static void SetError(Exception e) | |||
| 286 | 286 | ||
| 287 | 287 | IntPtr op = CLRObject.GetInstHandle(e); | |
| 288 | 288 | IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); | |
| 289 | - Runtime.PyErr_SetObject(etype, op); | ||
| 289 | + Runtime.PyErr_SetObject(new BorrowedReference(etype), new BorrowedReference(op)); | ||
| 290 | 290 | Runtime.XDecref(etype); | |
| 291 | 291 | Runtime.XDecref(op); | |
| 292 | 292 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,5 @@ | |||
| 1 | 1 | using System; | |
| 2 | + using System.Collections.Generic; | ||
| 2 | 3 | using System.Runtime.InteropServices; | |
| 3 | 4 | ||
| 4 | 5 | namespace Python.Runtime | |
@@ -222,22 +223,12 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) | |||
| 222 | 223 | // Check these BEFORE the built-in import runs; may as well | |
| 223 | 224 | // do the Incref()ed return here, since we've already found | |
| 224 | 225 | // the module. | |
| 225 | - if (mod_name == "clr") | ||
| 226 | + if (mod_name == "clr" || mod_name == "CLR") | ||
| 226 | 227 | { | |
| 227 | - IntPtr clr_module = GetCLRModule(fromList); | ||
| 228 | - if (clr_module != IntPtr.Zero) | ||
| 228 | + if (mod_name == "CLR") | ||
| 229 | 229 | { | |
| 230 | - IntPtr sys_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'."); | ||
| 235 | 231 | } | |
| 236 | - return clr_module; | ||
| 237 | - } | ||
| 238 | - if (mod_name == "CLR") | ||
| 239 | - { | ||
| 240 | - Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'."); | ||
| 241 | 232 | IntPtr clr_module = GetCLRModule(fromList); | |
| 242 | 233 | if (clr_module != IntPtr.Zero) | |
| 243 | 234 | { | |
@@ -249,8 +240,10 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) | |||
| 249 | 240 | } | |
| 250 | 241 | return clr_module; | |
| 251 | 242 | } | |
| 243 | + | ||
| 252 | 244 | string realname = mod_name; | |
| 253 | 245 | string clr_prefix = null; | |
| 246 | + | ||
| 254 | 247 | if (mod_name.StartsWith("CLR.")) | |
| 255 | 248 | { | |
| 256 | 249 | clr_prefix = "CLR."; // prepend when adding the module to sys.modules | |
@@ -312,11 +305,22 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) | |||
| 312 | 305 | AssemblyManager.UpdatePath(); | |
| 313 | 306 | if (!AssemblyManager.IsValidNamespace(realname)) | |
| 314 | 307 | { | |
| 315 | - if (!AssemblyManager.LoadImplicit(realname)) | ||
| 308 | + var loadExceptions = new List<Exception>(); | ||
| 309 | + if (!AssemblyManager.LoadImplicit(realname, assemblyLoadErrorHandler: loadExceptions.Add)) | ||
| 316 | 310 | { | |
| 317 | 311 | // May be called when a module being imported imports a module. | |
| 318 | 312 | // In particular, I've seen decimal import copy import org.python.core | |
| 319 | - return Runtime.PyObject_Call(py_import, args, kw); | ||
| 313 | + IntPtr importResult = Runtime.PyObject_Call(py_import, args, kw); | ||
| 314 | + // TODO: use ModuleNotFoundError in Python 3.6+ | ||
| 315 | + if (importResult == IntPtr.Zero && loadExceptions.Count > 0 | ||
| 316 | + && Exceptions.ExceptionMatches(Exceptions.ImportError)) | ||
| 317 | + { | ||
| 318 | + loadExceptions.Add(new PythonException()); | ||
| 319 | + var importError = new PyObject(new BorrowedReference(Exceptions.ImportError)); | ||
| 320 | + importError.SetAttr("__cause__", new AggregateException(loadExceptions).ToPython()); | ||
| 321 | + Runtime.PyErr_SetObject(new BorrowedReference(Exceptions.ImportError), importError.Reference); | ||
| 322 | + } | ||
| 323 | + return importResult; | ||
| 320 | 324 | } | |
| 321 | 325 | } | |
| 322 | 326 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -291,8 +291,8 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth | |||
| 291 | 291 | IntPtr valueList = Runtime.PyDict_Values(kw); | |
| 292 | 292 | for (int i = 0; i < pynkwargs; ++i) | |
| 293 | 293 | { | |
| 294 | - var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(keylist, i)); | ||
| 295 | - kwargDict[keyStr] = Runtime.PyList_GetItem(valueList, i).DangerousGetAddress(); | ||
| 294 | + var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i)); | ||
| 295 | + kwargDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress(); | ||
| 296 | 296 | } | |
| 297 | 297 | Runtime.XDecref(keylist); | |
| 298 | 298 | Runtime.XDecref(valueList); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -119,7 +119,7 @@ public ManagedType GetAttribute(string name, bool guess) | |||
| 119 | 119 | // cost. Ask the AssemblyManager to do implicit loading for each | |
| 120 | 120 | // of the steps in the qualified name, then try it again. | |
| 121 | 121 | bool ignore = name.StartsWith("__"); | |
| 122 | - if (AssemblyManager.LoadImplicit(qname, !ignore)) | ||
| 122 | + if (AssemblyManager.LoadImplicit(qname, assemblyLoadErrorHandler: ImportWarning, !ignore)) | ||
| 123 | 123 | { | |
| 124 | 124 | if (AssemblyManager.IsValidNamespace(qname)) | |
| 125 | 125 | { | |
@@ -161,6 +161,11 @@ public ManagedType GetAttribute(string name, bool guess) | |||
| 161 | 161 | return null; | |
| 162 | 162 | } | |
| 163 | 163 | ||
| 164 | + static void ImportWarning(Exception exception) | ||
| 165 | + { | ||
| 166 | + Exceptions.warn(exception.ToString(), Exceptions.ImportWarning); | ||
| 167 | + } | ||
| 168 | + | ||
| 164 | 169 | ||
| 165 | 170 | /// <summary> | |
| 166 | 171 | /// Stores an attribute in the instance dict for future lookups. | |
@@ -365,7 +370,7 @@ internal void InitializePreload() | |||
| 365 | 370 | if (interactive_preload) | |
| 366 | 371 | { | |
| 367 | 372 | interactive_preload = false; | |
| 368 | - if (Runtime.PySys_GetObject("ps1") != IntPtr.Zero) | ||
| 373 | + if (!Runtime.PySys_GetObject("ps1").IsNull) | ||
| 369 | 374 | { | |
| 370 | 375 | preload = true; | |
| 371 | 376 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,11 @@ public PyList(IntPtr ptr) : base(ptr) | |||
| 22 | 22 | { | |
| 23 | 23 | } | |
| 24 | 24 | ||
| 25 | + /// <summary> | ||
| 26 | + /// Creates new <see cref="PyList"/> pointing to the same object, as the given reference. | ||
| 27 | + /// </summary> | ||
| 28 | + internal PyList(BorrowedReference reference) : base(reference) { } | ||
| 29 | + | ||
| 25 | 30 | ||
| 26 | 31 | /// <summary> | |
| 27 | 32 | /// PyList Constructor | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,8 @@ protected PySequence(IntPtr ptr) : base(ptr) | |||
| 16 | 16 | { | |
| 17 | 17 | } | |
| 18 | 18 | ||
| 19 | + internal PySequence(BorrowedReference reference) : base(reference) { } | ||
| 20 | + | ||
| 19 | 21 | protected PySequence() | |
| 20 | 22 | { | |
| 21 | 23 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,15 @@ public PyTuple(IntPtr ptr) : base(ptr) | |||
| 22 | 22 | { | |
| 23 | 23 | } | |
| 24 | 24 | ||
| 25 | + /// <summary> | ||
| 26 | + /// PyTuple Constructor | ||
| 27 | + /// </summary> | ||
| 28 | + /// <remarks> | ||
| 29 | + /// Creates a new PyTuple from an existing object reference. | ||
| 30 | + /// The object reference is not checked for type-correctness. | ||
| 31 | + /// </remarks> | ||
| 32 | + internal PyTuple(BorrowedReference reference) : base(reference) { } | ||
| 33 | + | ||
| 25 | 34 | ||
| 26 | 35 | /// <summary> | |
| 27 | 36 | /// PyTuple Constructor | |
| Back | FazBrowse Home | New Git URL |
0 commit comments