From 008c5fe74c81a0ee35462cf1cb7d8caa21a04f2a Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Sat, 12 Dec 2020 20:39:54 +0100 Subject: [PATCH] Drop the long-deprecated CLR.* alias --- CHANGELOG.md | 1 + src/runtime/importhook.cs | 80 +++++------- src/runtime/runtime.cs | 1 - src/runtime/typemanager.cs | 2 +- src/testing/threadtest.cs | 4 +- src/tests/test_clrmethod.py | 2 +- src/tests/test_compat.py | 233 ----------------------------------- src/tests/test_exceptions.py | 2 +- src/tests/test_method.py | 6 +- 9 files changed, 42 insertions(+), 289 deletions(-) delete mode 100644 src/tests/test_compat.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aa1944eb..9afccbf2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ details about the cause of the failure if you need to "downcast" to the implementation class. - BREAKING: Parameters marked with `ParameterAttributes.Out` are no longer returned in addition to the regular method return value (unless they are passed with `ref` or `out` keyword). +- BREAKING: Drop support for the long-deprecated CLR.* prefix. ### Fixed diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index 3f318fd1c..d8f7e4dcc 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -124,7 +124,7 @@ internal static void Shutdown() internal static void SaveRuntimeData(RuntimeDataStorage storage) { - // Increment the reference counts here so that the objects don't + // Increment the reference counts here so that the objects don't // get freed in Shutdown. Runtime.XIncref(py_clr_module); Runtime.XIncref(root.pyHandle); @@ -241,12 +241,8 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) // Check these BEFORE the built-in import runs; may as well // do the Incref()ed return here, since we've already found // the module. - if (mod_name == "clr" || mod_name == "CLR") + if (mod_name == "clr") { - if (mod_name == "CLR") - { - Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'."); - } IntPtr clr_module = GetCLRModule(fromList); if (clr_module != IntPtr.Zero) { @@ -262,51 +258,41 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) string realname = mod_name; string clr_prefix = null; - if (mod_name.StartsWith("CLR.")) + // 2010-08-15: Always seemed smart to let python try first... + // This shaves off a few tenths of a second on test_module.py + // and works around a quirk where 'sys' is found by the + // LoadImplicit() deprecation logic. + // Turns out that the AssemblyManager.ResolveHandler() checks to see if any + // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very + // little sense to me. + IntPtr res = Runtime.PyObject_Call(py_import, args, kw); + if (res != IntPtr.Zero) { - clr_prefix = "CLR."; // prepend when adding the module to sys.modules - realname = mod_name.Substring(4); - string msg = $"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly."; - Exceptions.deprecation(msg); - } - else - { - // 2010-08-15: Always seemed smart to let python try first... - // This shaves off a few tenths of a second on test_module.py - // and works around a quirk where 'sys' is found by the - // LoadImplicit() deprecation logic. - // Turns out that the AssemblyManager.ResolveHandler() checks to see if any - // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very - // little sense to me. - IntPtr res = Runtime.PyObject_Call(py_import, args, kw); - if (res != IntPtr.Zero) + // There was no error. + if (fromlist && IsLoadAll(fromList)) { - // There was no error. - if (fromlist && IsLoadAll(fromList)) - { - var mod = ManagedType.GetManagedObject(res) as ModuleObject; - mod?.LoadNames(); - } - return res; - } - // There was an error - if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) - { - // and it was NOT an ImportError; bail out here. - return IntPtr.Zero; + var mod = ManagedType.GetManagedObject(res) as ModuleObject; + mod?.LoadNames(); } + return res; + } + // There was an error + if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) + { + // and it was NOT an ImportError; bail out here. + return IntPtr.Zero; + } - if (mod_name == string.Empty) - { - // Most likely a missing relative import. - // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists: - // from . import _html5lib - // We don't support them anyway - return IntPtr.Zero; - } - // Otherwise, just clear the it. - Exceptions.Clear(); + if (mod_name == string.Empty) + { + // Most likely a missing relative import. + // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists: + // from . import _html5lib + // We don't support them anyway + return IntPtr.Zero; } + // Otherwise, just clear the it. + Exceptions.Clear(); string[] names = realname.Split('.'); @@ -372,7 +358,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) // Add the module to sys.modules Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle); - // If imported from CLR add CLR. to sys.modules as well + // If imported from CLR add clr. to sys.modules as well if (clr_prefix != null) { Runtime.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle); diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index d9301acdc..4cb8db71f 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -492,7 +492,6 @@ private static void ClearClrModules() private static void RemoveClrRootModule() { var modules = PyImport_GetModuleDict(); - PyDictTryDelItem(modules, "CLR"); PyDictTryDelItem(modules, "clr"); PyDictTryDelItem(modules, "clr._extra"); } diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index b1403081e..89ccdea4c 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -176,7 +176,7 @@ internal static IntPtr CreateType(Type impl) internal static IntPtr CreateType(ManagedType impl, Type clrType) { // Cleanup the type name to get rid of funny nested type names. - string name = "CLR." + clrType.FullName; + string name = $"clr.{clrType.FullName}"; int i = name.LastIndexOf('+'); if (i > -1) { diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs index 2825c3fef..9c76929b2 100644 --- a/src/testing/threadtest.cs +++ b/src/testing/threadtest.cs @@ -11,8 +11,8 @@ public class ThreadTest private static PyObject module; private static string testmod = - "import CLR\n" + - "from CLR.Python.Test import ThreadTest\n" + + "import clr\n" + + "from Python.Test import ThreadTest\n" + "\n" + "def echostring(value):\n" + " return value\n" + diff --git a/src/tests/test_clrmethod.py b/src/tests/test_clrmethod.py index a6078bece..0c63f9c59 100644 --- a/src/tests/test_clrmethod.py +++ b/src/tests/test_clrmethod.py @@ -14,7 +14,7 @@ def __init__(self): @clr.clrmethod(int, [int]) def test(self, x): return x*2 - + def get_X(self): return self._x def set_X(self, value): diff --git a/src/tests/test_compat.py b/src/tests/test_compat.py deleted file mode 100644 index ec36e3be0..000000000 --- a/src/tests/test_compat.py +++ /dev/null @@ -1,233 +0,0 @@ -# -*- coding: utf-8 -*- -# TODO: Complete removal of methods below. Similar to test_module - -"""Backward-compatibility tests for deprecated features.""" - -import clr -import types - -import pytest - -from .utils import is_clr_class, is_clr_module, is_clr_root_module - - -# Tests for old-style CLR-prefixed module naming. -def test_simple_import(): - """Test simple import.""" - import CLR - assert is_clr_root_module(CLR) - assert CLR.__name__ == 'clr' - - import sys - assert isinstance(sys, types.ModuleType) - assert sys.__name__ == 'sys' - - import http.client - assert isinstance(http.client, types.ModuleType) - assert http.client.__name__ == 'http.client' - - -def test_simple_import_with_alias(): - """Test simple import with aliasing.""" - import CLR as myCLR - assert is_clr_root_module(myCLR) - assert myCLR.__name__ == 'clr' - - import sys as mySys - assert isinstance(mySys, types.ModuleType) - assert mySys.__name__ == 'sys' - - import http.client as myHttplib - assert isinstance(myHttplib, types.ModuleType) - assert myHttplib.__name__ == 'http.client' - - -def test_dotted_name_import(): - """Test dotted-name import.""" - import CLR.System - assert is_clr_module(CLR.System) - assert CLR.System.__name__ == 'System' - - import System - assert is_clr_module(System) - assert System.__name__ == 'System' - - assert System is CLR.System - - import xml.dom - assert isinstance(xml.dom, types.ModuleType) - assert xml.dom.__name__ == 'xml.dom' - - -def test_dotted_name_import_with_alias(): - """Test dotted-name import with aliasing.""" - import CLR.System as myCLRSystem - assert is_clr_module(myCLRSystem) - assert myCLRSystem.__name__ == 'System' - - import System as mySystem - assert is_clr_module(mySystem) - assert mySystem.__name__ == 'System' - - assert mySystem is myCLRSystem - - import xml.dom as myDom - assert isinstance(myDom, types.ModuleType) - assert myDom.__name__ == 'xml.dom' - - -def test_simple_import_from(): - """Test simple 'import from'.""" - from CLR import System - assert is_clr_module(System) - assert System.__name__ == 'System' - - from xml import dom - assert isinstance(dom, types.ModuleType) - assert dom.__name__ == 'xml.dom' - - -def test_simple_import_from_with_alias(): - """Test simple 'import from' with aliasing.""" - from CLR import System as mySystem - assert is_clr_module(mySystem) - assert mySystem.__name__ == 'System' - - from xml import dom as myDom - assert isinstance(myDom, types.ModuleType) - assert myDom.__name__ == 'xml.dom' - - -def test_dotted_name_import_from(): - """Test dotted-name 'import from'.""" - from CLR.System import Xml - assert is_clr_module(Xml) - assert Xml.__name__ == 'System.Xml' - - from CLR.System.Xml import XmlDocument - assert is_clr_class(XmlDocument) - assert XmlDocument.__name__ == 'XmlDocument' - - from xml.dom import pulldom - assert isinstance(pulldom, types.ModuleType) - assert pulldom.__name__ == 'xml.dom.pulldom' - - from xml.dom.pulldom import PullDOM - assert isinstance(PullDOM, type) - assert PullDOM.__name__ == 'PullDOM' - - -def test_dotted_name_import_from_with_alias(): - """Test dotted-name 'import from' with aliasing.""" - from CLR.System import Xml as myXml - assert is_clr_module(myXml) - assert myXml.__name__ == 'System.Xml' - - from CLR.System.Xml import XmlDocument as myXmlDocument - assert is_clr_class(myXmlDocument) - assert myXmlDocument.__name__ == 'XmlDocument' - - from xml.dom import pulldom as myPulldom - assert isinstance(myPulldom, types.ModuleType) - assert myPulldom.__name__ == 'xml.dom.pulldom' - - from xml.dom.pulldom import PullDOM as myPullDOM - assert isinstance(myPullDOM, type) - assert myPullDOM.__name__ == 'PullDOM' - - -def test_from_module_import_star(): - """Test from module import * behavior.""" - clr.AddReference('System.Management') - - count = len(locals().keys()) - m = __import__('CLR.System.Management', globals(), locals(), ['*']) - assert m.__name__ == 'System.Management' - assert is_clr_module(m) - assert len(locals().keys()) > count + 1 - - m2 = __import__('System.Management', globals(), locals(), ['*']) - assert m2.__name__ == 'System.Management' - assert is_clr_module(m2) - assert len(locals().keys()) > count + 1 - - assert m is m2 - - -def test_explicit_assembly_load(): - """Test explicit assembly loading using standard CLR tools.""" - from CLR.System.Reflection import Assembly - from CLR import System - import sys - - assembly = Assembly.LoadWithPartialName('System.Data') - assert assembly is not None - - import CLR.System.Data - assert 'System.Data' in sys.modules - - assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') - assert assembly is None - - -def test_implicit_load_already_valid_namespace(): - """Test implicit assembly load over an already valid namespace.""" - # In this case, the mscorlib assembly (loaded by default) defines - # a number of types in the System namespace. There is also a System - # assembly, which is _not_ loaded by default, which also contains - # types in the System namespace. The desired behavior is for the - # Python runtime to "do the right thing", allowing types from both - # assemblies to be found in the CLR.System module implicitly. - import CLR.System - assert is_clr_class(CLR.System.UriBuilder) - - -def test_import_non_existant_module(): - """Test import failure for a non-existent module.""" - with pytest.raises(ImportError): - import System.SpamSpamSpam - - with pytest.raises(ImportError): - import CLR.System.SpamSpamSpam - - -def test_lookup_no_namespace_type(): - """Test lookup of types without a qualified namespace.""" - import CLR.Python.Test - import CLR - assert is_clr_class(CLR.NoNamespaceType) - - -def test_module_lookup_recursion(): - """Test for recursive lookup handling.""" - with pytest.raises(ImportError): - from CLR import CLR - - with pytest.raises(AttributeError): - import CLR - _ = CLR.CLR - - -def test_module_get_attr(): - """Test module getattr behavior.""" - import CLR.System as System - - int_type = System.Int32 - assert is_clr_class(int_type) - - module = System.Xml - assert is_clr_module(module) - - with pytest.raises(AttributeError): - _ = System.Spam - - with pytest.raises(TypeError): - _ = getattr(System, 1) - - -def test_multiple_imports(): - # import CLR did raise a Seg Fault once - # test if the Exceptions.warn() method still causes it - for _ in range(100): - import CLR - _ = CLR diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index 02d3005aa..7fafeebcb 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -291,7 +291,7 @@ def test_exception_is_instance_of_system_object(): # classes, we wrap managed exceptions in a general-purpose old-style # class that delegates to the wrapped object. This makes _almost_ # everything work as expected, except that an isinstance check against - # CLR.System.Object will fail for a managed exception (because a new + # System.Object will fail for a managed exception (because a new # style class cannot appear in the __bases__ of an old-style class # without causing a crash in the CPython interpreter). This test is # here mainly to remind me to update the caveat in the documentation diff --git a/src/tests/test_method.py b/src/tests/test_method.py index 344734642..c7859e881 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -928,7 +928,7 @@ def test_getting_generic_method_binding_does_not_leak_memory(): PlainOldClass().GenericMethod[str] gc.collect() - clr.System.GC.Collect() + System.GC.Collect() processBytesAfterCall = process.memory_info().rss print("Memory consumption (bytes) at end of test: " + str(processBytesAfterCall)) @@ -969,7 +969,7 @@ def test_getting_overloaded_method_binding_does_not_leak_memory(): PlainOldClass().OverloadedMethod.Overloads[int] gc.collect() - clr.System.GC.Collect() + System.GC.Collect() processBytesAfterCall = process.memory_info().rss print("Memory consumption (bytes) at end of test: " + str(processBytesAfterCall)) @@ -1010,7 +1010,7 @@ def test_getting_method_overloads_binding_does_not_leak_memory(): PlainOldClass().OverloadedMethod.Overloads gc.collect() - clr.System.GC.Collect() + System.GC.Collect() processBytesAfterCall = process.memory_info().rss print("Memory consumption (bytes) at end of test: " + str(processBytesAfterCall))