PythonTestCases()
+ {
+ // Add the test that you want to debug here.
+ yield return new[] { "test_enum", "test_enum_standard_attrs" };
+ yield return new[] { "test_generic", "test_missing_generic_type" };
+ }
+
+ ///
+ /// Runs a test in src/tests/*.py as an embedded test. This facilitates debugging.
+ ///
+ /// The file name without extension
+ /// The name of the test method
+ [TestCaseSource(nameof(PythonTestCases))]
+ public void RunPythonTest(string testFile, string testName)
+ {
+ // Find the tests directory
+ string folder = typeof(PythonTestRunner).Assembly.Location;
+ while (Path.GetFileName(folder) != "src")
+ {
+ folder = Path.GetDirectoryName(folder);
+ }
+ folder = Path.Combine(folder, "tests");
+ string path = Path.Combine(folder, testFile + ".py");
+ if (!File.Exists(path)) throw new FileNotFoundException("Cannot find test file", path);
+
+ // We could use 'import' below, but importlib gives more helpful error messages than 'import'
+ // https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
+ // Because the Python tests sometimes have relative imports, the module name must be inside the tests package
+ PythonEngine.Exec($@"
+import sys
+import os
+sys.path.append(os.path.dirname(r'{folder}'))
+sys.path.append(os.path.join(r'{folder}', 'fixtures'))
+import clr
+clr.AddReference('Python.Test')
+import tests
+module_name = 'tests.{testFile}'
+file_path = r'{path}'
+import importlib.util
+spec = importlib.util.spec_from_file_location(module_name, file_path)
+module = importlib.util.module_from_spec(spec)
+sys.modules[module_name] = module
+try:
+ spec.loader.exec_module(module)
+except ImportError as error:
+ raise ImportError(str(error) + ' when sys.path=' + os.pathsep.join(sys.path))
+module.{testName}()
+");
+ }
+ }
+}
From 0ccc443d905afa56f04ec48ffdfddf61b3a13955 Mon Sep 17 00:00:00 2001
From: Tom Minka <8955276+tminka@users.noreply.github.com>
Date: Mon, 4 Jan 2021 23:06:48 +0000
Subject: [PATCH 2/4] ImportHook preserves the original exception message when
an import fails
---
.github/workflows/main.yml | 4 ++--
src/runtime/importhook.cs | 5 ++++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3ca6a27bb..7c53d7522 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -53,9 +53,9 @@ jobs:
run: dotnet test --runtime any-${{ matrix.platform }} src/embed_tests/
if: ${{ matrix.os != 'macos' }} # Not working right now, doesn't find libpython
- - name: Python tests runner
+ - name: Python tests run from .NET
run: dotnet test --runtime any-${{ matrix.platform }} src/python_tests_runner/
- if: ${{ matrix.os != 'macos' }} # Not working right now, doesn't find libpython
+ if: ${{ matrix.os == 'windows' }} # Not working for others right now
# TODO: Run perf tests
# TODO: Run mono tests on Windows?
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index d8f7e4dcc..c5c81e0c3 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -291,6 +291,9 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
// We don't support them anyway
return IntPtr.Zero;
}
+ // Save the exception
+ var originalException = new PythonException();
+ var originalExceptionMessage = originalException.ToString();
// Otherwise, just clear the it.
Exceptions.Clear();
@@ -342,7 +345,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
ManagedType mt = tail.GetAttribute(name, true);
if (!(mt is ModuleObject))
{
- Exceptions.SetError(Exceptions.ImportError, $"No module named {name}");
+ Exceptions.SetError(Exceptions.ImportError, originalExceptionMessage);
return IntPtr.Zero;
}
if (head == null)
From 0a88f27fa19959a6cf0c7f0ca43e5c1720839a39 Mon Sep 17 00:00:00 2001
From: Tom Minka <8955276+tminka@users.noreply.github.com>
Date: Tue, 5 Jan 2021 00:27:36 +0000
Subject: [PATCH 3/4] Use PythonException.Restore
---
src/runtime/importhook.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index c5c81e0c3..af6174188 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -293,7 +293,6 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
}
// Save the exception
var originalException = new PythonException();
- var originalExceptionMessage = originalException.ToString();
// Otherwise, just clear the it.
Exceptions.Clear();
@@ -345,7 +344,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
ManagedType mt = tail.GetAttribute(name, true);
if (!(mt is ModuleObject))
{
- Exceptions.SetError(Exceptions.ImportError, originalExceptionMessage);
+ originalException.Restore();
return IntPtr.Zero;
}
if (head == null)
From 4ac44fee0edaa5da94c18266bc5126921a2e60a6 Mon Sep 17 00:00:00 2001
From: Tom Minka <8955276+tminka@users.noreply.github.com>
Date: Tue, 5 Jan 2021 00:31:53 +0000
Subject: [PATCH 4/4] Updated CHANGELOG
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1442075ef..53c45f419 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,6 +44,7 @@ details about the cause of the failure
- Made it possible to call `ToString`, `GetHashCode`, and `GetType` on inteface objects
- Fixed objects returned by enumerating `PyObject` being disposed too soon
- Incorrectly using a non-generic type with type parameters now produces a helpful Python error instead of throwing NullReferenceException
+- `import` may now raise errors with more detail than "No module named X"
### Removed
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy