Skip to content

Commit ab87b0a

Browse files
committed
[GR-16960] Honor '__all__' attribute during import.
PullRequest: graalpython/579
2 parents 1d5a53c + a3f393f commit ab87b0a

File tree

8 files changed

+311
-8
lines changed

8 files changed

+311
-8
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
"""PACKAGE DOC"""
41+
42+
from .lib import *
43+
from . import exported
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
__testname__ = "package1.exported"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
from . import moduleX
41+
from . import exported
42+
43+
__all__ = ["moduleX"]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
__testname__ = "package1.lib.exported"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
pass

graalpython/com.oracle.graal.python.test/src/tests/test_imports.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,9 @@ def test_imp_cached_imports():
147147

148148
spec = finder.find_spec("encodings.utf_8", None)
149149
assert not spec.submodule_search_locations
150+
151+
152+
def test_import_package_all() :
153+
import package1
154+
assert hasattr(package1, "moduleX"), "'package1' does not have attribute 'moduleX'"
155+
assert package1.exported.__testname__ == "package1.exported", "expected 'test_import_package_all' but was '%s'" % str(package1.exported.__testname__)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialAttributeNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,5 @@ public abstract class SpecialAttributeNames {
7474
public static final String __ITEMSIZE__ = "__itemsize__";
7575
public static final String __WEAKREF__ = "__weakref__";
7676
public static final String __WEAKLISTOFFSET__ = "__weaklistoffset__";
77+
public static final String __ALL__ = "__all__";
7778
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/ImportStarNode.java

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,43 @@
2525
*/
2626
package com.oracle.graal.python.nodes.statement;
2727

28+
import com.oracle.graal.python.builtins.objects.PNone;
2829
import com.oracle.graal.python.builtins.objects.dict.PDict;
2930
import com.oracle.graal.python.builtins.objects.function.PArguments;
3031
import com.oracle.graal.python.builtins.objects.mappingproxy.PMappingproxy;
3132
import com.oracle.graal.python.builtins.objects.module.PythonModule;
3233
import com.oracle.graal.python.builtins.objects.object.PythonObject;
34+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
35+
import com.oracle.graal.python.nodes.SpecialMethodNames;
36+
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
3337
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
38+
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
39+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
40+
import com.oracle.graal.python.nodes.subscript.GetItemNode;
3441
import com.oracle.graal.python.nodes.subscript.SetItemNode;
42+
import com.oracle.graal.python.nodes.util.CastToIndexNode;
43+
import com.oracle.graal.python.nodes.util.CastToStringNode;
44+
import com.oracle.graal.python.runtime.exception.PException;
3545
import com.oracle.truffle.api.CompilerDirectives;
46+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
3647
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
3748
import com.oracle.truffle.api.frame.VirtualFrame;
3849

3950
public class ImportStarNode extends AbstractImportNode {
51+
52+
@Child private SetItemNode dictWriteNode;
53+
@Child private SetAttributeNode.Dynamic setAttributeNode;
54+
@Child private GetAttributeNode getAttributeNode;
55+
@Child private LookupAndCallUnaryNode callLenNode;
56+
@Child private GetItemNode getItemNode;
57+
@Child private CastToIndexNode castToIndexNode;
58+
@Child private CastToStringNode castToStringNode;
59+
60+
@CompilationFinal private IsBuiltinClassProfile isAttributeErrorProfile;
61+
4062
private final String moduleName;
4163
private final int level;
4264

43-
@Child private SetItemNode dictWriteNode = null;
44-
@Child private SetAttributeNode.Dynamic setAttributeNode = null;
45-
4665
// TODO: remove once we removed PythonModule globals
4766

4867
private void writeAttribute(VirtualFrame frame, PythonObject globals, String name, Object value) {
@@ -70,16 +89,87 @@ public ImportStarNode(String moduleName, int level) {
7089
public void executeVoid(VirtualFrame frame) {
7190
Object importedModule = importModule(frame, moduleName, PArguments.getGlobals(frame), new String[]{"*"}, level);
7291
PythonObject globals = PArguments.getGlobals(frame);
92+
93+
String[] exportedModuleAttrs;
94+
Object attrAll;
95+
boolean skip_leading_underscores = true;
96+
try {
97+
attrAll = ensureGetAttributeNode().executeObject(frame, importedModule);
98+
} catch (PException e) {
99+
e.expectAttributeError(ensureIsAttributeErrorProfile());
100+
attrAll = PNone.NO_VALUE;
101+
}
102+
103+
if (attrAll != PNone.NO_VALUE) {
104+
int n = ensureCastToIndexNode().execute(ensureCallLenNode().executeObject(frame, attrAll));
105+
exportedModuleAttrs = new String[n];
106+
for (int i = 0; i < n; i++) {
107+
exportedModuleAttrs[i] = ensureCastToStringNode().execute(frame, ensureGetItemNode().executeWith(frame, attrAll, i));
108+
}
109+
skip_leading_underscores = false;
110+
} else {
111+
exportedModuleAttrs = getModuleAttrs(importedModule);
112+
}
113+
73114
assert importedModule instanceof PythonModule;
74-
for (String name : getModuleAttrs(importedModule)) {
75-
if (name.startsWith("__")) {
76-
continue;
115+
for (String name : exportedModuleAttrs) {
116+
// only skip attributes with leading '__' if there was no '__all__' attribute (see
117+
// 'ceval.c: import_all_from')
118+
if (!(skip_leading_underscores && name.startsWith("__"))) {
119+
Object attr = ((PythonModule) importedModule).getAttribute(name);
120+
writeAttribute(frame, globals, name, attr);
77121
}
78-
Object attr = ((PythonModule) importedModule).getAttribute(name);
79-
writeAttribute(frame, globals, name, attr);
80122
}
81123
}
82124

125+
private GetAttributeNode ensureGetAttributeNode() {
126+
if (getAttributeNode == null) {
127+
CompilerDirectives.transferToInterpreterAndInvalidate();
128+
getAttributeNode = insert(GetAttributeNode.create(SpecialAttributeNames.__ALL__));
129+
}
130+
return getAttributeNode;
131+
}
132+
133+
private LookupAndCallUnaryNode ensureCallLenNode() {
134+
if (callLenNode == null) {
135+
CompilerDirectives.transferToInterpreterAndInvalidate();
136+
callLenNode = insert(LookupAndCallUnaryNode.create(SpecialMethodNames.__LEN__));
137+
}
138+
return callLenNode;
139+
}
140+
141+
private CastToIndexNode ensureCastToIndexNode() {
142+
if (castToIndexNode == null) {
143+
CompilerDirectives.transferToInterpreterAndInvalidate();
144+
castToIndexNode = insert(CastToIndexNode.create());
145+
}
146+
return castToIndexNode;
147+
}
148+
149+
private GetItemNode ensureGetItemNode() {
150+
if (getItemNode == null) {
151+
CompilerDirectives.transferToInterpreterAndInvalidate();
152+
getItemNode = insert(GetItemNode.create());
153+
}
154+
return getItemNode;
155+
}
156+
157+
private CastToStringNode ensureCastToStringNode() {
158+
if (castToStringNode == null) {
159+
CompilerDirectives.transferToInterpreterAndInvalidate();
160+
castToStringNode = insert(CastToStringNode.create());
161+
}
162+
return castToStringNode;
163+
}
164+
165+
private IsBuiltinClassProfile ensureIsAttributeErrorProfile() {
166+
if (isAttributeErrorProfile == null) {
167+
CompilerDirectives.transferToInterpreterAndInvalidate();
168+
isAttributeErrorProfile = IsBuiltinClassProfile.create();
169+
}
170+
return isAttributeErrorProfile;
171+
}
172+
83173
@TruffleBoundary
84174
private static String[] getModuleAttrs(Object importedModule) {
85175
return ((PythonModule) importedModule).getAttributeNames().toArray(new String[0]);

0 commit comments

Comments
 (0)