Skip to content

Commit ded36bf

Browse files
committed
refactor: Maintain exports order (__all__)
1 parent eca9626 commit ded36bf

6 files changed

Lines changed: 16 additions & 12 deletions

File tree

src/_griffe/agents/inspector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ def handle_attribute(self, node: ObjectNode, annotation: str | Expr | None = Non
526526
parent.set_member(node.name, attribute)
527527

528528
if node.name == "__all__":
529-
parent.exports = set(node.obj)
529+
parent.exports = list(node.obj)
530530
self.extensions.call("on_instance", node=node, obj=attribute, agent=self)
531531
self.extensions.call("on_attribute_instance", node=node, attr=attribute, agent=self)
532532

src/_griffe/agents/visitor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ def visit_augassign(self, node: ast.AugAssign) -> None:
638638
and isinstance(node.op, ast.Add)
639639
)
640640
if all_augment:
641-
# we assume exports is not None at this point
641+
# We assume `exports` is not `None` at this point.
642642
self.current.exports.extend( # type: ignore[union-attr]
643643
[
644644
name if isinstance(name, str) else ExprName(name.name, parent=name.parent)

src/_griffe/loader.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def expand_exports(self, module: Module, seen: set | None = None) -> None:
269269
if module.exports is None:
270270
return
271271

272-
expanded = set()
272+
expanded = []
273273
for export in module.exports:
274274
# It's a name: we resolve it, get the module it comes from,
275275
# recurse into it, and add its exports to the current ones.
@@ -283,12 +283,12 @@ def expand_exports(self, module: Module, seen: set | None = None) -> None:
283283
if next_module.path not in seen:
284284
self.expand_exports(next_module, seen)
285285
try:
286-
expanded |= next_module.exports
286+
expanded += [export for export in next_module.exports if export not in expanded]
287287
except TypeError:
288288
logger.warning("Unsupported item in %s.__all__: %s (use strings only)", module.path, export)
289289
# It's a string, simply add it to the current exports.
290290
else:
291-
expanded.add(export)
291+
expanded.append(export)
292292
module.exports = expanded
293293

294294
# Make sure to expand exports in all modules.

src/_griffe/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ def __init__(
455455
while the values are the actual names of the objects (`from ... import REAL_NAME as ...`).
456456
"""
457457

458-
self.exports: set[str] | list[str | ExprName] | None = None
458+
self.exports: list[str | ExprName] | None = None
459459
"""The names of the objects exported by this (module) object through the `__all__` variable.
460460
461461
Exports can contain string (object names) or resolvable names,
@@ -1276,7 +1276,7 @@ def imports(self) -> dict[str, str]:
12761276
return self.final_target.imports
12771277

12781278
@property
1279-
def exports(self) -> set[str] | list[str | ExprName] | None:
1279+
def exports(self) -> list[str | ExprName] | None:
12801280
"""The names of the objects exported by this (module) object through the `__all__` variable.
12811281
12821282
Exports can contain string (object names) or resolvable names,

tests/test_models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_submodule_exports() -> None:
3636
assert sub.is_wildcard_exposed
3737

3838
assert not private.is_wildcard_exposed
39-
root.exports = {"_private"}
39+
root.exports = ["_private"]
4040
assert private.is_wildcard_exposed
4141

4242

tests/test_visitor.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,19 @@ def absolute(self, path: str | Path) -> str | Path:
172172
@pytest.mark.parametrize(
173173
"statements",
174174
[
175-
"""__all__ = moda_all + modb_all + modc_all + ["CONST_INIT"]""",
175+
"""__all__ = ["CONST_INIT"] + moda_all + modb_all + modc_all""",
176176
"""__all__ = ["CONST_INIT", *moda_all, *modb_all, *modc_all]""",
177177
"""
178178
__all__ = ["CONST_INIT"]
179179
__all__ += moda_all + modb_all + modc_all
180180
""",
181181
"""
182-
__all__ = moda_all + modb_all + modc_all
183-
__all__ += ["CONST_INIT"]
182+
__all__ = ["CONST_INIT"] + moda_all + modb_all
183+
__all__ += modc_all
184+
""",
185+
"""
186+
__all__ = ["CONST_INIT"] + moda_all + modb_all
187+
__all__ += [*modc_all]
184188
""",
185189
"""
186190
__all__ = ["CONST_INIT"]
@@ -215,7 +219,7 @@ def test_parse_complex__all__assignments(statements: str) -> None:
215219
package = loader.load(tmp_package.name)
216220
loader.resolve_aliases()
217221

218-
assert package.exports == {"CONST_INIT", "CONST_A", "CONST_B", "CONST_C"}
222+
assert package.exports == ["CONST_INIT", "CONST_A", "CONST_B", "CONST_C"]
219223

220224

221225
def test_dont_crash_on_nested_functions_in_init() -> None:

0 commit comments

Comments
 (0)