11using System ;
2+ using System . Collections . Generic ;
23using System . Runtime . InteropServices ;
34
45namespace Python . Runtime
@@ -222,22 +223,12 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
222223 // Check these BEFORE the built-in import runs; may as well
223224 // do the Incref()ed return here, since we've already found
224225 // the module.
225- if ( mod_name == "clr" )
226+ if ( mod_name == "clr" || mod_name == "CLR" )
226227 {
227- IntPtr clr_module = GetCLRModule ( fromList ) ;
228- if ( clr_module != IntPtr . Zero )
228+ if ( mod_name == "CLR" )
229229 {
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'." ) ;
235231 }
236- return clr_module ;
237- }
238- if ( mod_name == "CLR" )
239- {
240- Exceptions . deprecation ( "The CLR module is deprecated. Please use 'clr'." ) ;
241232 IntPtr clr_module = GetCLRModule ( fromList ) ;
242233 if ( clr_module != IntPtr . Zero )
243234 {
@@ -249,53 +240,45 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
249240 }
250241 return clr_module ;
251242 }
243+
252244 string realname = mod_name ;
253245 string clr_prefix = null ;
254- if ( mod_name . StartsWith ( "CLR." ) )
255- {
256- clr_prefix = "CLR." ; // prepend when adding the module to sys.modules
257- realname = mod_name . Substring ( 4 ) ;
258- string msg = $ "Importing from the CLR.* namespace is deprecated. Please import '{ realname } ' directly.";
259- Exceptions . deprecation ( msg ) ;
260- }
261- else
246+
247+ // 2010-08-15: Always seemed smart to let python try first...
248+ // This shaves off a few tenths of a second on test_module.py
249+ // and works around a quirk where 'sys' is found by the
250+ // LoadImplicit() deprecation logic.
251+ // Turns out that the AssemblyManager.ResolveHandler() checks to see if any
252+ // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
253+ // little sense to me.
254+ IntPtr res = Runtime . PyObject_Call ( py_import , args , kw ) ;
255+ if ( res != IntPtr . Zero )
262256 {
263- // 2010-08-15: Always seemed smart to let python try first...
264- // This shaves off a few tenths of a second on test_module.py
265- // and works around a quirk where 'sys' is found by the
266- // LoadImplicit() deprecation logic.
267- // Turns out that the AssemblyManager.ResolveHandler() checks to see if any
268- // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
269- // little sense to me.
270- IntPtr res = Runtime . PyObject_Call ( py_import , args , kw ) ;
271- if ( res != IntPtr . Zero )
272- {
273- // There was no error.
274- if ( fromlist && IsLoadAll ( fromList ) )
275- {
276- var mod = ManagedType . GetManagedObject ( res ) as ModuleObject ;
277- mod ? . LoadNames ( ) ;
278- }
279- return res ;
280- }
281- // There was an error
282- if ( ! Exceptions . ExceptionMatches ( Exceptions . ImportError ) )
257+ // There was no error.
258+ if ( fromlist && IsLoadAll ( fromList ) )
283259 {
284- // and it was NOT an ImportError; bail out here.
285- return IntPtr . Zero ;
260+ var mod = ManagedType . GetManagedObject ( res ) as ModuleObject ;
261+ mod ? . LoadNames ( ) ;
286262 }
263+ return res ;
264+ }
265+ // There was an error
266+ if ( ! Exceptions . ExceptionMatches ( Exceptions . ImportError ) )
267+ {
268+ // and it was NOT an ImportError; bail out here.
269+ return IntPtr . Zero ;
270+ }
287271
288- if ( mod_name == string . Empty )
289- {
290- // Most likely a missing relative import.
291- // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
292- // from . import _html5lib
293- // We don't support them anyway
294- return IntPtr . Zero ;
295- }
296- // Otherwise, just clear the it.
297- Exceptions . Clear ( ) ;
272+ if ( mod_name == string . Empty )
273+ {
274+ // Most likely a missing relative import.
275+ // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
276+ // from . import _html5lib
277+ // We don't support them anyway
278+ return IntPtr . Zero ;
298279 }
280+ // Otherwise, just clear the it.
281+ Exceptions . Clear ( ) ;
299282
300283 string [ ] names = realname . Split ( '.' ) ;
301284
@@ -312,11 +295,22 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
312295 AssemblyManager . UpdatePath ( ) ;
313296 if ( ! AssemblyManager . IsValidNamespace ( realname ) )
314297 {
315- if ( ! AssemblyManager . LoadImplicit ( realname ) )
298+ var loadExceptions = new List < Exception > ( ) ;
299+ if ( ! AssemblyManager . LoadImplicit ( realname , assemblyLoadErrorHandler : loadExceptions . Add ) )
316300 {
317301 // May be called when a module being imported imports a module.
318302 // In particular, I've seen decimal import copy import org.python.core
319- return Runtime . PyObject_Call ( py_import , args , kw ) ;
303+ IntPtr importResult = Runtime . PyObject_Call ( py_import , args , kw ) ;
304+ // TODO: use ModuleNotFoundError in Python 3.6+
305+ if ( importResult == IntPtr . Zero && loadExceptions . Count > 0
306+ && Exceptions . ExceptionMatches ( Exceptions . ImportError ) )
307+ {
308+ loadExceptions . Add ( new PythonException ( ) ) ;
309+ var importError = new PyObject ( new BorrowedReference ( Exceptions . ImportError ) ) ;
310+ importError . SetAttr ( "__cause__" , new AggregateException ( loadExceptions ) . ToPython ( ) ) ;
311+ Runtime . PyErr_SetObject ( new BorrowedReference ( Exceptions . ImportError ) , importError . Reference ) ;
312+ }
313+ return importResult ;
320314 }
321315 }
322316
0 commit comments