From 69f5aed9a9af21cd5fec3bd6aba43397408462a5 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Thu, 23 Sep 2021 20:03:07 -0700 Subject: [PATCH 1/2] simplify assembly ResolveHandler, and use official assembly name parsing method --- src/runtime/assemblymanager.cs | 36 +++++++++++++++++++++++----------- tests/test_module.py | 6 +++--- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index d44f5f666..a107b4f46 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -110,16 +110,15 @@ private static void AssemblyLoadHandler(object ob, AssemblyLoadEventArgs args) /// private static Assembly ResolveHandler(object ob, ResolveEventArgs args) { - string name = args.Name.ToLower(); - foreach (Assembly a in assemblies) + var name = new AssemblyName(args.Name); + foreach (var alreadyLoaded in assemblies) { - string full = a.FullName.ToLower(); - if (full.StartsWith(name)) + if (AssemblyName.ReferenceMatchesDefinition(name, alreadyLoaded.GetName())) { - return a; + return alreadyLoaded; } } - return LoadAssemblyPath(args.Name); + return LoadAssemblyPath(name.Name); } @@ -154,6 +153,17 @@ internal static void UpdatePath() } } + /// + /// Given an assembly name, try to find this assembly file using the + /// PYTHONPATH. If not found, return null to indicate implicit load + /// using standard load semantics (app base directory then GAC, etc.) + /// + public static string FindAssembly(AssemblyName name) + { + if (name is null) throw new ArgumentNullException(nameof(name)); + + return FindAssembly(name.Name); + } /// /// Given an assembly name, try to find this assembly file using the @@ -162,8 +172,13 @@ internal static void UpdatePath() /// public static string FindAssembly(string name) { - char sep = Path.DirectorySeparatorChar; + if (name is null) throw new ArgumentNullException(nameof(name)); + return FindAssemblyCandidates(name).FirstOrDefault(); + } + + static IEnumerable FindAssemblyCandidates(string name) + { foreach (string head in pypath) { string path; @@ -173,22 +188,21 @@ public static string FindAssembly(string name) } else { - path = head + sep + name; + path = Path.Combine(head, name); } string temp = path + ".dll"; if (File.Exists(temp)) { - return temp; + yield return temp; } temp = path + ".exe"; if (File.Exists(temp)) { - return temp; + yield return temp; } } - return null; } diff --git a/tests/test_module.py b/tests/test_module.py index d0378e91e..3737dccf6 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -232,11 +232,11 @@ def test_explicit_assembly_load(): from System.Reflection import Assembly import System, sys - assembly = Assembly.LoadWithPartialName('System.Runtime') + assembly = Assembly.LoadWithPartialName('Microsoft.CSharp') assert assembly is not None - import System.Runtime - assert 'System.Runtime' in sys.modules + import Microsoft.CSharp + assert 'Microsoft.CSharp' in sys.modules assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') assert assembly is None From 904fe328cc4a89dc471a61b7b0ce5a9cbd8ee06a Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Thu, 23 Sep 2021 22:37:51 -0700 Subject: [PATCH 2/2] fixed ImportHook not seeing namespaces in assemblies loaded via direct call to Assembly.Load* methods --- src/runtime/assemblymanager.cs | 5 ++++- src/runtime/importhook.cs | 24 ++++++++++++++++++++---- src/runtime/moduleobject.cs | 9 +++++++-- src/runtime/native/TypeOffset.cs | 3 ++- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index a107b4f46..74720e1a6 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -290,7 +290,10 @@ internal static void ScanAssembly(Assembly assembly) for (var n = 0; n < names.Length; n++) { s = n == 0 ? names[0] : s + "." + names[n]; - namespaces.TryAdd(s, new ConcurrentDictionary()); + if (namespaces.TryAdd(s, new ConcurrentDictionary())) + { + ImportHook.AddNamespace(s); + } } } diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index d3592c15d..0feb06b89 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -1,6 +1,5 @@ using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; +using System.Collections.Concurrent; namespace Python.Runtime { @@ -37,6 +36,9 @@ def find_spec(klass, fullname, paths=None, target=None): if 'clr' not in sys.modules: return None clr = sys.modules['clr'] + + clr._add_pending_namespaces() + if clr._available_namespaces and fullname in clr._available_namespaces: return importlib.machinery.ModuleSpec(fullname, DotNetLoader(), is_package=True) return None @@ -169,12 +171,26 @@ static void TeardownNameSpaceTracking() Runtime.PyDict_SetItemString(root.dict, availableNsKey, Runtime.PyNone); } - public static void AddNamespace(string name) + static readonly ConcurrentQueue addPending = new(); + public static void AddNamespace(string name) => addPending.Enqueue(name); + + internal static int AddPendingNamespaces() + { + int added = 0; + while (addPending.TryDequeue(out string ns)) + { + AddNamespaceWithGIL(ns); + added++; + } + return added; + } + + internal static void AddNamespaceWithGIL(string name) { var pyNs = Runtime.PyString_FromString(name); try { - var nsSet = Runtime.PyDict_GetItemString(new BorrowedReference(root.dict), availableNsKey); + var nsSet = Runtime.PyDict_GetItemString(root.DictRef, availableNsKey); if (!(nsSet.IsNull || nsSet.DangerousGetAddress() == Runtime.PyNone)) { if (Runtime.PySet_Add(nsSet, new BorrowedReference(pyNs)) != 0) diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index c2614b1d8..569d2e00c 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -535,8 +535,9 @@ public static Assembly AddReference(string name) // method because it may be called from other threads, leading to deadlocks // if it is called while Python code is executing. var currNs = AssemblyManager.GetNamespaces().Except(origNs); - foreach(var ns in currNs){ - ImportHook.AddNamespace(ns); + foreach(var ns in currNs) + { + ImportHook.AddNamespaceWithGIL(ns); } return assembly; } @@ -602,5 +603,9 @@ public static ModuleObject _load_clr_module(PyObject spec) mod = ImportHook.Import(modname.ToString()); return mod; } + + [ModuleFunction] + [ForbidPythonThreads] + public static int _add_pending_namespaces() => ImportHook.AddPendingNamespaces(); } } diff --git a/src/runtime/native/TypeOffset.cs b/src/runtime/native/TypeOffset.cs index b5957a9c7..a3b4f4a24 100644 --- a/src/runtime/native/TypeOffset.cs +++ b/src/runtime/native/TypeOffset.cs @@ -161,7 +161,8 @@ static void ValidateRequiredOffsetsPresent(PropertyInfo[] offsetProperties) "Initialize", "InitializeSlots", "ListAssemblies", - "_load_clr_module", + nameof(CLRModule._load_clr_module), + nameof(CLRModule._add_pending_namespaces), "Release", "Reset", "set_SuppressDocs", 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