Skip to content

Commit dc69411

Browse files
authored
Name missing from __all__ on re-import (#2717)
* Adjust test_import to always trigger error-case * Ensure that names are added to __all__ exactly once
1 parent 4e61c18 commit dc69411

2 files changed

Lines changed: 19 additions & 12 deletions

File tree

src/runtime/Types/ModuleObject.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal class ModuleObject : ExtensionType
1919
internal PyDict dict;
2020
protected string _namespace;
2121
private readonly PyList __all__ = new ();
22+
private readonly HashSet<string> allNames = new();
2223

2324
// Attributes to be set on the module according to PEP302 and 451
2425
// by the import machinery.
@@ -178,22 +179,23 @@ public void LoadNames()
178179
{
179180
foreach (string name in AssemblyManager.GetNames(_namespace))
180181
{
181-
cache.TryGetValue(name, out var m);
182-
if (m != null)
182+
bool hasValidAttribute = cache.TryGetValue(name, out var m);
183+
if (!hasValidAttribute)
183184
{
184-
continue;
185-
}
186-
BorrowedReference attr = Runtime.PyDict_GetItemString(dict, name);
187-
// If __dict__ has already set a custom property, skip it.
188-
if (!attr.IsNull)
189-
{
190-
continue;
185+
BorrowedReference attr = Runtime.PyDict_GetItemString(dict, name);
186+
// If __dict__ has already set a custom property, skip it.
187+
if (!attr.IsNull)
188+
{
189+
continue;
190+
}
191+
192+
using var attrVal = GetAttribute(name, true);
193+
hasValidAttribute = !attrVal.IsNull();
191194
}
192195

193-
using var attrVal = GetAttribute(name, true);
194-
if (!attrVal.IsNull())
196+
if (hasValidAttribute && allNames.Add(name))
195197
{
196-
// if it's a valid attribute, add it to __all__
198+
// if it's a valid attribute, add it to __all__ once.
197199
using var pyname = Runtime.PyString_FromString(name);
198200
if (Runtime.PyList_Append(__all__, pyname.Borrow()) != 0)
199201
{

tests/test_import.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
import pytest
66
import sys
77

8+
# Unused import to preload the class
9+
#
10+
# This resulted in the FileStream name missing from the wildcard import later
11+
from System.IO import FileStream # noqa: F401
12+
813
def test_relative_missing_import():
914
"""Test that a relative missing import doesn't crash.
1015
Some modules use this to check if a package is installed.

0 commit comments

Comments
 (0)