Skip to content

Commit be5812c

Browse files
committed
Python: from <pkg> import * ignores __all__ regression
Notice that `has_defined_all_indirection` all have both `all_defined_bar_copy` and `all_defined_foo_copy` marked as exported, even though only `all_defined_foo_copy` is available.
1 parent d77ce4f commit be5812c

File tree

5 files changed

+134
-5
lines changed

5 files changed

+134
-5
lines changed

python/ql/test/experimental/import-resolution/ModuleExport.expected

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,53 @@
7676
| foo | print | trace.py:7:1:7:27 | ControlFlowNode for FunctionExpr |
7777
| foo | print_function | trace.py:1:24:1:37 | ControlFlowNode for ImportMember |
7878
| foo | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
79+
| has_defined_all | __all__ | has_defined_all.py:7:11:7:29 | ControlFlowNode for List |
80+
| has_defined_all | __all__ | trace.py:52:11:52:46 | ControlFlowNode for List |
81+
| has_defined_all | __file__ | has_defined_all.py:2:7:2:14 | ControlFlowNode for __file__ |
82+
| has_defined_all | __file__ | has_defined_all.py:9:6:9:13 | ControlFlowNode for __file__ |
83+
| has_defined_all | _indent_level | trace.py:3:17:3:17 | ControlFlowNode for IntegerLiteral |
84+
| has_defined_all | _print | trace.py:5:10:5:14 | ControlFlowNode for print |
85+
| has_defined_all | _status | trace.py:21:11:21:11 | ControlFlowNode for IntegerLiteral |
86+
| has_defined_all | all_defined_bar | has_defined_all.py:5:19:5:35 | ControlFlowNode for Str |
87+
| has_defined_all | all_defined_foo | has_defined_all.py:4:19:4:35 | ControlFlowNode for Str |
88+
| has_defined_all | check | trace.py:26:1:26:61 | ControlFlowNode for FunctionExpr |
89+
| has_defined_all | enter | trace.py:11:1:11:21 | ControlFlowNode for FunctionExpr |
90+
| has_defined_all | exit | trace.py:16:1:16:20 | ControlFlowNode for FunctionExpr |
91+
| has_defined_all | print | trace.py:7:1:7:27 | ControlFlowNode for FunctionExpr |
92+
| has_defined_all | print_function | trace.py:1:24:1:37 | ControlFlowNode for ImportMember |
93+
| has_defined_all | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
94+
| has_defined_all_copy | __all__ | has_defined_all_copy.py:9:11:9:34 | ControlFlowNode for List |
95+
| has_defined_all_copy | __all__ | trace.py:52:11:52:46 | ControlFlowNode for List |
96+
| has_defined_all_copy | __file__ | has_defined_all_copy.py:4:7:4:14 | ControlFlowNode for __file__ |
97+
| has_defined_all_copy | __file__ | has_defined_all_copy.py:11:6:11:13 | ControlFlowNode for __file__ |
98+
| has_defined_all_copy | _indent_level | trace.py:3:17:3:17 | ControlFlowNode for IntegerLiteral |
99+
| has_defined_all_copy | _print | trace.py:5:10:5:14 | ControlFlowNode for print |
100+
| has_defined_all_copy | _status | trace.py:21:11:21:11 | ControlFlowNode for IntegerLiteral |
101+
| has_defined_all_copy | all_defined_bar_copy | has_defined_all_copy.py:7:24:7:45 | ControlFlowNode for Str |
102+
| has_defined_all_copy | all_defined_foo_copy | has_defined_all_copy.py:6:24:6:45 | ControlFlowNode for Str |
103+
| has_defined_all_copy | check | trace.py:26:1:26:61 | ControlFlowNode for FunctionExpr |
104+
| has_defined_all_copy | enter | trace.py:11:1:11:21 | ControlFlowNode for FunctionExpr |
105+
| has_defined_all_copy | exit | trace.py:16:1:16:20 | ControlFlowNode for FunctionExpr |
106+
| has_defined_all_copy | print | trace.py:7:1:7:27 | ControlFlowNode for FunctionExpr |
107+
| has_defined_all_copy | print_function | trace.py:1:24:1:37 | ControlFlowNode for ImportMember |
108+
| has_defined_all_copy | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
109+
| has_defined_all_indirection | __all__ | has_defined_all_copy.py:9:11:9:34 | ControlFlowNode for List |
110+
| has_defined_all_indirection | __all__ | trace.py:52:11:52:46 | ControlFlowNode for List |
111+
| has_defined_all_indirection | __file__ | has_defined_all_copy.py:4:7:4:14 | ControlFlowNode for __file__ |
112+
| has_defined_all_indirection | __file__ | has_defined_all_copy.py:11:6:11:13 | ControlFlowNode for __file__ |
113+
| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:2:7:2:14 | ControlFlowNode for __file__ |
114+
| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:6:6:6:13 | ControlFlowNode for __file__ |
115+
| has_defined_all_indirection | _indent_level | trace.py:3:17:3:17 | ControlFlowNode for IntegerLiteral |
116+
| has_defined_all_indirection | _print | trace.py:5:10:5:14 | ControlFlowNode for print |
117+
| has_defined_all_indirection | _status | trace.py:21:11:21:11 | ControlFlowNode for IntegerLiteral |
118+
| has_defined_all_indirection | all_defined_bar_copy | has_defined_all_copy.py:7:24:7:45 | ControlFlowNode for Str |
119+
| has_defined_all_indirection | all_defined_foo_copy | has_defined_all_copy.py:6:24:6:45 | ControlFlowNode for Str |
120+
| has_defined_all_indirection | check | trace.py:26:1:26:61 | ControlFlowNode for FunctionExpr |
121+
| has_defined_all_indirection | enter | trace.py:11:1:11:21 | ControlFlowNode for FunctionExpr |
122+
| has_defined_all_indirection | exit | trace.py:16:1:16:20 | ControlFlowNode for FunctionExpr |
123+
| has_defined_all_indirection | print | trace.py:7:1:7:27 | ControlFlowNode for FunctionExpr |
124+
| has_defined_all_indirection | print_function | trace.py:1:24:1:37 | ControlFlowNode for ImportMember |
125+
| has_defined_all_indirection | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
79126
| if_then_else | __all__ | trace.py:52:11:52:46 | ControlFlowNode for List |
80127
| if_then_else | __file__ | if_then_else.py:2:7:2:14 | ControlFlowNode for __file__ |
81128
| if_then_else | __file__ | if_then_else.py:16:6:16:13 | ControlFlowNode for __file__ |
@@ -106,25 +153,39 @@
106153
| if_then_else_refined | src | if_then_else_refined.py:11:11:11:16 | ControlFlowNode for SOURCE |
107154
| if_then_else_refined | src | if_then_else_refined.py:13:11:13:16 | ControlFlowNode for SOURCE |
108155
| if_then_else_refined | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
156+
| main | __all__ | has_defined_all.py:7:11:7:29 | ControlFlowNode for List |
157+
| main | __all__ | has_defined_all_copy.py:9:11:9:34 | ControlFlowNode for List |
109158
| main | __all__ | trace.py:52:11:52:46 | ControlFlowNode for List |
159+
| main | __file__ | has_defined_all.py:2:7:2:14 | ControlFlowNode for __file__ |
160+
| main | __file__ | has_defined_all.py:9:6:9:13 | ControlFlowNode for __file__ |
161+
| main | __file__ | has_defined_all_copy.py:4:7:4:14 | ControlFlowNode for __file__ |
162+
| main | __file__ | has_defined_all_copy.py:11:6:11:13 | ControlFlowNode for __file__ |
163+
| main | __file__ | has_defined_all_indirection.py:2:7:2:14 | ControlFlowNode for __file__ |
164+
| main | __file__ | has_defined_all_indirection.py:6:6:6:13 | ControlFlowNode for __file__ |
110165
| main | __file__ | main.py:24:7:24:14 | ControlFlowNode for __file__ |
111-
| main | __file__ | main.py:107:6:107:13 | ControlFlowNode for __file__ |
166+
| main | __file__ | main.py:149:6:149:13 | ControlFlowNode for __file__ |
112167
| main | __file__ | package/subpackage2/__init__.py:2:7:2:14 | ControlFlowNode for __file__ |
113168
| main | __file__ | package/subpackage2/__init__.py:6:6:6:13 | ControlFlowNode for __file__ |
114169
| main | _indent_level | trace.py:3:17:3:17 | ControlFlowNode for IntegerLiteral |
115170
| main | _print | trace.py:5:10:5:14 | ControlFlowNode for print |
116171
| main | _status | trace.py:21:11:21:11 | ControlFlowNode for IntegerLiteral |
117172
| main | aliased_subpackage | main.py:54:21:54:52 | ControlFlowNode for ImportMember |
118173
| main | aliased_subpackage | main.py:65:8:65:25 | ControlFlowNode for ImportExpr |
174+
| main | all_defined_bar | has_defined_all.py:5:19:5:35 | ControlFlowNode for Str |
175+
| main | all_defined_bar_copy | has_defined_all_copy.py:7:24:7:45 | ControlFlowNode for Str |
176+
| main | all_defined_foo | has_defined_all.py:4:19:4:35 | ControlFlowNode for Str |
177+
| main | all_defined_foo_copy | has_defined_all_copy.py:6:24:6:45 | ControlFlowNode for Str |
119178
| main | bar_attr | main.py:42:17:42:24 | ControlFlowNode for ImportMember |
120179
| main | check | trace.py:26:1:26:61 | ControlFlowNode for FunctionExpr |
121180
| main | clashing_attr | main.py:83:24:83:36 | ControlFlowNode for ImportMember |
122181
| main | enter | trace.py:11:1:11:21 | ControlFlowNode for FunctionExpr |
123182
| main | exit | trace.py:16:1:16:20 | ControlFlowNode for FunctionExpr |
124183
| main | foo | main.py:27:8:27:10 | ControlFlowNode for ImportExpr |
125184
| main | foo_alias | main.py:34:8:34:10 | ControlFlowNode for ImportExpr |
126-
| main | if_then_else_defined | main.py:93:26:93:45 | ControlFlowNode for ImportMember |
127-
| main | if_then_else_refined | main.py:100:8:100:27 | ControlFlowNode for ImportExpr |
185+
| main | has_defined_all | main.py:100:8:100:22 | ControlFlowNode for ImportExpr |
186+
| main | has_defined_all_indirection | main.py:118:8:118:34 | ControlFlowNode for ImportExpr |
187+
| main | if_then_else_defined | main.py:135:26:135:45 | ControlFlowNode for ImportMember |
188+
| main | if_then_else_refined | main.py:142:8:142:27 | ControlFlowNode for ImportExpr |
128189
| main | local_import | main.py:57:1:57:19 | ControlFlowNode for FunctionExpr |
129190
| main | namespace_module_attr | main.py:79:52:79:72 | ControlFlowNode for ImportMember |
130191
| main | non_clashing_submodule | main.py:83:39:83:60 | ControlFlowNode for ImportMember |
@@ -134,8 +195,8 @@
134195
| main | print | trace.py:7:1:7:27 | ControlFlowNode for FunctionExpr |
135196
| main | print_function | main.py:21:24:21:37 | ControlFlowNode for ImportMember |
136197
| main | print_function | trace.py:1:24:1:37 | ControlFlowNode for ImportMember |
137-
| main | refined | main.py:97:8:97:14 | ControlFlowNode for ImportExpr |
138-
| main | simplistic_reexport | main.py:103:8:103:26 | ControlFlowNode for ImportExpr |
198+
| main | refined | main.py:139:8:139:14 | ControlFlowNode for ImportExpr |
199+
| main | simplistic_reexport | main.py:145:8:145:26 | ControlFlowNode for ImportExpr |
139200
| main | status | trace.py:23:1:23:13 | ControlFlowNode for FunctionExpr |
140201
| main | subpackage2_attr | package/subpackage2/__init__.py:4:20:4:37 | ControlFlowNode for Str |
141202
| main | subpackage_attr | main.py:46:32:46:46 | ControlFlowNode for ImportMember |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from trace import *
2+
enter(__file__)
3+
4+
all_defined_foo = "all_defined_foo"
5+
all_defined_bar = "all_defined_bar"
6+
7+
__all__ = ["all_defined_foo"]
8+
9+
exit(__file__)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# a copy of `has_defined_all.py` that is imported by `has_defined_all_indirection.py`
2+
# with its' own names such that we can check both `import *` without any cross-talk
3+
from trace import *
4+
enter(__file__)
5+
6+
all_defined_foo_copy = "all_defined_foo_copy"
7+
all_defined_bar_copy = "all_defined_bar_copy"
8+
9+
__all__ = ["all_defined_foo_copy"]
10+
11+
exit(__file__)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from trace import *
2+
enter(__file__)
3+
4+
from has_defined_all_copy import *
5+
6+
exit(__file__)

python/ql/test/experimental/import-resolution/main.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,48 @@ def local_import():
8484
check("clashing_attr", clashing_attr, "clashing_attr", globals()) #$ prints=clashing_attr SPURIOUS: prints="<module attr_clash.clashing_attr>"
8585
check("non_clashing_submodule", non_clashing_submodule, "<module attr_clash.non_clashing_submodule>", globals()) #$ prints="<module attr_clash.non_clashing_submodule>"
8686

87+
# check that import * only imports the __all__ attributes
88+
from has_defined_all import *
89+
check("all_defined_foo", all_defined_foo, "all_defined_foo", globals()) #$ prints=all_defined_foo
90+
91+
try:
92+
check("all_defined_bar", all_defined_bar, "all_defined_bar", globals()) #$ SPURIOUS: prints=all_defined_bar
93+
raise Exception("Did not get expected NameError")
94+
except NameError as e:
95+
if "all_defined_bar" in str(e):
96+
print("Got expected NameError:", e)
97+
else:
98+
raise
99+
100+
import has_defined_all # $ imports=has_defined_all as=has_defined_all
101+
check("has_defined_all.all_defined_foo", has_defined_all.all_defined_foo, "all_defined_foo", globals()) #$ prints=all_defined_foo
102+
check("has_defined_all.all_defined_bar", has_defined_all.all_defined_bar, "all_defined_bar", globals()) #$ prints=all_defined_bar
103+
104+
# same check as above, but going through one level of indirection (which can make a difference)
105+
from has_defined_all_indirection import *
106+
check("all_defined_foo_copy", all_defined_foo_copy, "all_defined_foo_copy", globals()) #$ prints=all_defined_foo_copy
107+
108+
try:
109+
check("all_defined_bar_copy", all_defined_bar_copy, "all_defined_bar_copy", globals()) #$ SPURIOUS: prints=all_defined_bar_copy
110+
raise Exception("Did not get expected NameError")
111+
except NameError as e:
112+
if "all_defined_bar_copy" in str(e):
113+
print("Got expected NameError:", e)
114+
else:
115+
raise
116+
117+
# same check as above, but going through one level of indirection (which can make a difference)
118+
import has_defined_all_indirection # $ imports=has_defined_all_indirection as=has_defined_all_indirection
119+
check("has_defined_all_indirection.all_defined_foo_copy", has_defined_all_indirection.all_defined_foo_copy, "all_defined_foo_copy", globals()) #$ prints=all_defined_foo_copy
120+
121+
try:
122+
check("has_defined_all_indirection.all_defined_bar_copy", has_defined_all_indirection.all_defined_bar_copy, "all_defined_bar_copy", globals()) #$ SPURIOUS: prints=all_defined_bar_copy
123+
raise Exception("Did not get expected AttributeError")
124+
except AttributeError as e:
125+
if "all_defined_bar_copy" in str(e):
126+
print("Got expected AttributeError:", e)
127+
else:
128+
raise
87129

88130
# check that import * from an __init__ file works
89131
from package.subpackage2 import *

0 commit comments

Comments
 (0)