diff --git a/src/runtime/Types/ModuleObject.cs b/src/runtime/Types/ModuleObject.cs index f641b393e..e525564b2 100644 --- a/src/runtime/Types/ModuleObject.cs +++ b/src/runtime/Types/ModuleObject.cs @@ -19,6 +19,7 @@ internal class ModuleObject : ExtensionType internal PyDict dict; protected string _namespace; private readonly PyList __all__ = new (); + private readonly HashSet allNames = new(); // Attributes to be set on the module according to PEP302 and 451 // by the import machinery. @@ -178,22 +179,23 @@ public void LoadNames() { foreach (string name in AssemblyManager.GetNames(_namespace)) { - cache.TryGetValue(name, out var m); - if (m != null) + bool hasValidAttribute = cache.TryGetValue(name, out var m); + if (!hasValidAttribute) { - continue; - } - BorrowedReference attr = Runtime.PyDict_GetItemString(dict, name); - // If __dict__ has already set a custom property, skip it. - if (!attr.IsNull) - { - continue; + BorrowedReference attr = Runtime.PyDict_GetItemString(dict, name); + // If __dict__ has already set a custom property, skip it. + if (!attr.IsNull) + { + continue; + } + + using var attrVal = GetAttribute(name, true); + hasValidAttribute = !attrVal.IsNull(); } - using var attrVal = GetAttribute(name, true); - if (!attrVal.IsNull()) + if (hasValidAttribute && allNames.Add(name)) { - // if it's a valid attribute, add it to __all__ + // if it's a valid attribute, add it to __all__ once. using var pyname = Runtime.PyString_FromString(name); if (Runtime.PyList_Append(__all__, pyname.Borrow()) != 0) { diff --git a/tests/test_import.py b/tests/test_import.py index 877eacd84..f90192190 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -5,6 +5,11 @@ import pytest import sys +# Unused import to preload the class +# +# This resulted in the FileStream name missing from the wildcard import later +from System.IO import FileStream # noqa: F401 + def test_relative_missing_import(): """Test that a relative missing import doesn't crash. Some modules use this to check if a package is installed.