Skip to content

Commit 6296884

Browse files
committed
better handling of __module__ property for types and methods, added tests
1 parent 1d8ee01 commit 6296884

File tree

4 files changed

+133
-4
lines changed

4 files changed

+133
-4
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright (c) 2018, 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+
41+
def test_builtins():
42+
import array
43+
assert array.array.__module__ == "array" # builtin class
44+
assert int.__module__ == "builtins" # builtin class
45+
import sys
46+
assert sys.getrecursionlimit.__module__ == "sys" # builtin module method
47+
48+
def test_imported():
49+
import code
50+
assert code.InteractiveInterpreter.__module__ == "code" # class
51+
assert code.InteractiveInterpreter.runsource.__module__ == "code" # function
52+
assert code.InteractiveInterpreter().runsource.__module__ == "code" # method
53+
54+
class TestClass():
55+
def foo(self):
56+
pass
57+
58+
def test_user_class():
59+
assert TestClass.__module__ == __name__
60+
assert TestClass().__module__ == __name__
61+
assert TestClass.foo.__module__ == __name__
62+
assert TestClass().foo.__module__ == __name__
63+
# test redefine:
64+
TestClass.__module__ = "bar"
65+
assert TestClass.__module__ == "bar"
66+
t = TestClass()
67+
t.__module__ = "baz"
68+
assert t.__module__ == "baz"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,9 @@ private void initializeTypes() {
491491
// publish builtin types in the corresponding modules
492492
for (PythonBuiltinClassType builtinClass : PythonBuiltinClassType.VALUES) {
493493
String module = builtinClass.getPublicInModule();
494-
PythonBuiltinClass clazz = lookupType(builtinClass);
495494
if (module != null) {
496-
lookupBuiltinModule(module).setAttribute(builtinClass.getName(), clazz);
495+
lookupBuiltinModule(module).setAttribute(builtinClass.getName(), lookupType(builtinClass));
497496
}
498-
clazz.setAttribute("__module__", module == null ? "builtins" : module);
499497
}
500498
// now initialize well-known objects
501499
pyTrue = new PInt(lookupType(PythonBuiltinClassType.Boolean), BigInteger.ONE);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/method/AbstractMethodBuiltins.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CODE__;
3030
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FUNC__;
31+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__MODULE__;
3132
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
3233
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__SELF__;
3334
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CALL__;
@@ -39,14 +40,21 @@
3940
import com.oracle.graal.python.builtins.CoreFunctions;
4041
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4142
import com.oracle.graal.python.builtins.PythonBuiltins;
43+
import com.oracle.graal.python.builtins.modules.BuiltinFunctions.GetAttrNode;
44+
import com.oracle.graal.python.builtins.objects.PNone;
4245
import com.oracle.graal.python.builtins.objects.function.PKeyword;
46+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
47+
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4348
import com.oracle.graal.python.nodes.argument.CreateArgumentsNode;
49+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
50+
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
4451
import com.oracle.graal.python.nodes.call.CallDispatchNode;
4552
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
4653
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
4754
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
4855
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
4956
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
57+
import com.oracle.truffle.api.CompilerDirectives;
5058
import com.oracle.truffle.api.dsl.Cached;
5159
import com.oracle.truffle.api.dsl.Fallback;
5260
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
@@ -149,4 +157,34 @@ boolean eq(@SuppressWarnings("unused") Object self, @SuppressWarnings("unused")
149157
return false;
150158
}
151159
}
160+
161+
@Builtin(name = __MODULE__, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
162+
@GenerateNodeFactory
163+
abstract static class GetModuleNode extends PythonBuiltinNode {
164+
@Specialization(guards = "isNoValue(none)")
165+
Object getModule(PythonObject self, @SuppressWarnings("unused") PNone none,
166+
@Cached("create()") ReadAttributeFromObjectNode readObject,
167+
@Cached("create()") GetAttrNode getAttr,
168+
@Cached("create()") WriteAttributeToObjectNode writeObject) {
169+
Object module = readObject.execute(self, __MODULE__);
170+
if (module == PNone.NO_VALUE) {
171+
CompilerDirectives.transferToInterpreter();
172+
Object globals = self instanceof PMethod ? ((PMethod) self).getSelf() : ((PBuiltinMethod) self).getSelf();
173+
if (globals instanceof PythonModule) {
174+
module = ((PythonModule) globals).getAttribute(__NAME__);
175+
} else {
176+
module = getAttr.execute(globals, __MODULE__, PNone.NONE);
177+
}
178+
writeObject.execute(self, __MODULE__, module);
179+
}
180+
return module;
181+
}
182+
183+
@Specialization(guards = "!isNoValue(value)")
184+
Object getModule(PythonObject self, Object value,
185+
@Cached("create()") WriteAttributeToObjectNode writeObject) {
186+
writeObject.execute(self, __MODULE__, value);
187+
return PNone.NONE;
188+
}
189+
}
152190
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,6 @@ boolean instanceCheck(PythonClass cls, Object derived) {
461461
@Builtin(name = __SUBCLASSES__, fixedNumOfPositionalArgs = 1)
462462
@GenerateNodeFactory
463463
static abstract class SubclassesNode extends PythonUnaryBuiltinNode {
464-
@Child private IsSubtypeNode isSubtypeNode = IsSubtypeNode.create();
465464

466465
@Specialization
467466
@TruffleBoundary
@@ -496,4 +495,30 @@ Object setName(PythonClass cls, Object value,
496495
return setName.execute(cls, __NAME__, value);
497496
}
498497
}
498+
499+
@Builtin(name = __MODULE__, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
500+
@GenerateNodeFactory
501+
static abstract class ModuleNode extends PythonBinaryBuiltinNode {
502+
503+
@Specialization(guards = "isNoValue(value)")
504+
@TruffleBoundary
505+
Object getModule(PythonClass cls, @SuppressWarnings("unused") PNone value) {
506+
if (cls instanceof PythonBuiltinClass) {
507+
String module = ((PythonBuiltinClass) cls).getType().getPublicInModule();
508+
return module == null ? "builtins" : module;
509+
}
510+
Object module = cls.getAttribute(__MODULE__);
511+
if (module == PNone.NO_VALUE) {
512+
throw raise(AttributeError, "");
513+
}
514+
return module;
515+
}
516+
517+
@Specialization(guards = "!isNoValue(value)")
518+
@TruffleBoundary
519+
Object setModule(PythonClass cls, Object value) {
520+
cls.setAttribute(__MODULE__, value);
521+
return PNone.NONE;
522+
}
523+
}
499524
}

0 commit comments

Comments
 (0)