From b123d58326464c7ecf3777d9e7fa8b6c254f6bee Mon Sep 17 00:00:00 2001 From: Tony Roberts Date: Wed, 9 Apr 2014 16:33:02 +0100 Subject: [PATCH] Move the implicit loading deprecation warning into LoadImplicit and use the assembly location in the warning instead of the namespace. Update test to check for the implicit loading warning. --- pythonnet/src/runtime/assemblymanager.cs | 34 +++++++++++------ pythonnet/src/runtime/importhook.cs | 11 +----- pythonnet/src/runtime/moduleobject.cs | 10 +---- pythonnet/src/testing/classtest.cs | 1 - pythonnet/src/testing/eventtest.cs | 17 --------- pythonnet/src/testing/generictest.cs | 1 - pythonnet/src/tests/test_class.py | 1 - pythonnet/src/tests/test_module.py | 47 +++++++++++------------- 8 files changed, 47 insertions(+), 75 deletions(-) diff --git a/pythonnet/src/runtime/assemblymanager.cs b/pythonnet/src/runtime/assemblymanager.cs index 3fc4a5feb..b07cde1c2 100644 --- a/pythonnet/src/runtime/assemblymanager.cs +++ b/pythonnet/src/runtime/assemblymanager.cs @@ -221,30 +221,40 @@ public static Assembly LoadAssemblyPath(string name) { // Call ONLY for namespaces that HAVE NOT been cached yet. //=================================================================== - public static bool LoadImplicit(string name, out bool fromFile) { - // 2010-08-16: Deprecation support - // Added out param to detect fully qualified name load - fromFile = false; + public static bool LoadImplicit(string name, bool warn=true) { string[] names = name.Split('.'); bool loaded = false; string s = ""; + Assembly lastAssembly = null; + HashSet assemblies = null; for (int i = 0; i < names.Length; i++) { s = (i == 0) ? names[0] : s + "." + names[i]; if (!probed.ContainsKey(s)) { - if (LoadAssemblyPath(s) != null) { - loaded = true; + if (assemblies == null) { + assemblies = new HashSet(AppDomain.CurrentDomain.GetAssemblies()); + } + Assembly a = LoadAssemblyPath(s); + if (a == null) { + a = LoadAssembly(s); } - else if (LoadAssembly(s) != null) { + if (a != null && !assemblies.Contains(a)) { loaded = true; + lastAssembly = a; } probed[s] = 1; - // 2010-12-24: Deprecation logic - if (loaded && (s == name)) { - fromFile = true; - //break; - } } } + + // Deprecation warning + if (warn && loaded) + { + string deprWarning = String.Format( + "\nThe module was found, but not in a referenced namespace.\n" + + "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", + Path.GetFileNameWithoutExtension(lastAssembly.Location)); + Exceptions.deprecation(deprWarning); + } + return loaded; } diff --git a/pythonnet/src/runtime/importhook.cs b/pythonnet/src/runtime/importhook.cs index 9d618b60d..c736f0645 100644 --- a/pythonnet/src/runtime/importhook.cs +++ b/pythonnet/src/runtime/importhook.cs @@ -156,15 +156,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { AssemblyManager.UpdatePath(); if (!AssemblyManager.IsValidNamespace(realname)) { - bool fromFile = false; - if (AssemblyManager.LoadImplicit(realname, out fromFile)) { - if (true == fromFile) { - string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" + - "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", realname); - Exceptions.deprecation(deprWarning); - } - } - else + if (!AssemblyManager.LoadImplicit(realname)) { // May be called when a module being imported imports a module. // In particular, I've seen decimal import copy import org.python.core @@ -174,7 +166,6 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { // See if sys.modules for this interpreter already has the // requested module. If so, just return the exising module. - IntPtr modules = Runtime.PyImport_GetModuleDict(); IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); diff --git a/pythonnet/src/runtime/moduleobject.cs b/pythonnet/src/runtime/moduleobject.cs index 3a3991947..efa916464 100644 --- a/pythonnet/src/runtime/moduleobject.cs +++ b/pythonnet/src/runtime/moduleobject.cs @@ -109,14 +109,8 @@ public ManagedType GetAttribute(string name, bool guess) { // thing happens with implicit assembly loading at a reasonable // cost. Ask the AssemblyManager to do implicit loading for each // of the steps in the qualified name, then try it again. - bool fromFile; - if (AssemblyManager.LoadImplicit(qname, out fromFile)) { - bool ignore = name.StartsWith("__"); - if (true == fromFile && (!ignore)) { - string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" + - "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", qname); - Exceptions.deprecation(deprWarning); - } + bool ignore = name.StartsWith("__"); + if (AssemblyManager.LoadImplicit(qname, !ignore)) { if (AssemblyManager.IsValidNamespace(qname)) { m = new ModuleObject(qname); StoreAttribute(name, m); diff --git a/pythonnet/src/testing/classtest.cs b/pythonnet/src/testing/classtest.cs index 08f4cb990..86239c9c5 100644 --- a/pythonnet/src/testing/classtest.cs +++ b/pythonnet/src/testing/classtest.cs @@ -9,7 +9,6 @@ using System; using System.Collections; -using System.Windows.Forms; namespace Python.Test { diff --git a/pythonnet/src/testing/eventtest.cs b/pythonnet/src/testing/eventtest.cs index 9ba25861e..c7f90da86 100644 --- a/pythonnet/src/testing/eventtest.cs +++ b/pythonnet/src/testing/eventtest.cs @@ -8,7 +8,6 @@ // ========================================================================== using System; -using System.Windows.Forms; namespace Python.Test { @@ -21,22 +20,6 @@ namespace Python.Test { public class EventTest { - - public void WinFormTest() { - EventTest e = new EventTest(); - EventHandler h = new EventHandler(e.ClickHandler); - - Form f = new Form(); - f.Click += h; - //f.Click(null, new EventArgs()); - f.Click -= h; - } - - public void ClickHandler(object sender, EventArgs e) { - Console.WriteLine("click"); - } - - public static event TestEventHandler PublicStaticEvent; protected static event TestEventHandler ProtectedStaticEvent; diff --git a/pythonnet/src/testing/generictest.cs b/pythonnet/src/testing/generictest.cs index 57bb146e7..c8f12ab2b 100644 --- a/pythonnet/src/testing/generictest.cs +++ b/pythonnet/src/testing/generictest.cs @@ -9,7 +9,6 @@ using System; using System.Collections; -using System.Windows.Forms; namespace Python.Test { diff --git a/pythonnet/src/tests/test_class.py b/pythonnet/src/tests/test_class.py index af635b5c0..ecc335999 100644 --- a/pythonnet/src/tests/test_class.py +++ b/pythonnet/src/tests/test_class.py @@ -6,7 +6,6 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # =========================================================================== - from System.Collections import Hashtable from Python.Test import ClassTest import sys, os, string, unittest, types diff --git a/pythonnet/src/tests/test_module.py b/pythonnet/src/tests/test_module.py index 401f03cc3..62ea78311 100644 --- a/pythonnet/src/tests/test_module.py +++ b/pythonnet/src/tests/test_module.py @@ -6,14 +6,13 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # =========================================================================== - import clr clr.AddReference('Python.Test') clr.AddReference('System.Data') # testImplicitAssemblyLoad() passes on deprecation warning; perfect! # ##clr.AddReference('System.Windows.Forms') -import sys, os, string, unittest, types +import sys, os, string, unittest, types, warnings class ModuleTests(unittest.TestCase): @@ -42,8 +41,8 @@ def test000importClr(self): def testPreloadVar(self): import clr self.assertTrue(clr.getPreload() is False, clr.getPreload()) - clr.setPreload(False) - self.assertTrue(clr.getPreload() is False, clr.getPreload()) + clr.setPreload(False) + self.assertTrue(clr.getPreload() is False, clr.getPreload()) try: clr.setPreload(True) self.assertTrue(clr.getPreload() is True, clr.getPreload()) @@ -204,27 +203,25 @@ def testFromModuleImportStar(self): def testImplicitAssemblyLoad(self): """Test implicit assembly loading via import.""" - # this test only applies to windows - if sys.platform != "win32": - return - - def test(): - # This should fail until System.Windows.Forms has been - # imported or that assembly has been explicitly loaded. - # True for Windows; Not so for Mono 2.8.1 - import System.Windows - - # The test fails when the project is compiled with MS VS 2005. Dunno why :( - # Fails (as expected) on Late Binding model. Works as expected on an interactive sesson. - self.assertRaises(ImportError, test) - - clr.AddReference("System.Windows.Forms") - import System.Windows.Forms as Forms - self.assertTrue(self.isCLRModule(Forms)) - self.assertTrue(Forms.__name__ == 'System.Windows.Forms') - from System.Windows.Forms import Form - self.assertTrue(self.isCLRClass(Form)) - self.assertTrue(Form.__name__ == 'Form') + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + + # should trigger a DeprecationWarning as Microsoft.Build hasn't + # been added as a reference yet (and should exist for mono) + import Microsoft.Build + + self.assertEqual(len(w), 1) + self.assertTrue(isinstance(w[0].message, DeprecationWarning)) + + with warnings.catch_warnings(record=True) as w: + clr.AddReference("System.Windows.Forms") + import System.Windows.Forms as Forms + self.assertTrue(self.isCLRModule(Forms)) + self.assertTrue(Forms.__name__ == 'System.Windows.Forms') + from System.Windows.Forms import Form + self.assertTrue(self.isCLRClass(Form)) + self.assertTrue(Form.__name__ == 'Form') + self.assertEqual(len(w), 0) def testExplicitAssemblyLoad(self):