Skip to content

Commit 28c3d5e

Browse files
committed
[GR-13361] module docstring
PullRequest: graalpython/356
2 parents c31bc60 + 9fabe7e commit 28c3d5e

File tree

6 files changed

+66
-9
lines changed

6 files changed

+66
-9
lines changed

graalpython/com.oracle.graal.python.test/src/tests/package/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -37,5 +37,7 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40+
"""PACKAGE DOC"""
41+
4042
from . import moduleY
4143
print("after importing moduleY")

graalpython/com.oracle.graal.python.test/src/tests/package/moduleA.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -37,4 +37,6 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40+
"""MODULE A DOC"""
41+
4042
print("module A")

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -51,6 +51,13 @@ def test_relative_import():
5151
raise e
5252

5353

54+
def test_module_docstring():
55+
import package
56+
assert package.__doc__ == "PACKAGE DOC"
57+
from package import moduleA
58+
assert moduleA.__doc__ == "MODULE A DOC"
59+
60+
5461
def test_dotted_import():
5562
# this is to prevent ides from optimising out the unused import
5663
try:

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2019, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -27,27 +27,45 @@
2727

2828
import com.oracle.graal.python.PythonLanguage;
2929
import com.oracle.graal.python.nodes.expression.ExpressionNode;
30+
import com.oracle.graal.python.nodes.frame.WriteGlobalNode;
3031
import com.oracle.truffle.api.CompilerAsserts;
32+
import com.oracle.truffle.api.CompilerDirectives;
3133
import com.oracle.truffle.api.frame.FrameDescriptor;
3234
import com.oracle.truffle.api.frame.FrameSlot;
3335
import com.oracle.truffle.api.frame.VirtualFrame;
3436
import com.oracle.truffle.api.source.SourceSection;
3537

38+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DOC__;
39+
3640
public class ModuleRootNode extends PClosureRootNode {
3741

3842
private final String name;
43+
private final String doc;
3944

4045
@Child private ExpressionNode body;
46+
@Child private WriteGlobalNode writeModuleDoc;
4147

42-
public ModuleRootNode(PythonLanguage language, String name, ExpressionNode file, FrameDescriptor descriptor, FrameSlot[] freeVarSlots) {
48+
public ModuleRootNode(PythonLanguage language, String name, String doc, ExpressionNode file, FrameDescriptor descriptor, FrameSlot[] freeVarSlots) {
4349
super(language, descriptor, freeVarSlots);
4450
this.name = "<module '" + name + "'>";
51+
this.doc = doc;
4552
this.body = file;
4653
}
4754

55+
private WriteGlobalNode getWriteModuleDoc() {
56+
if (writeModuleDoc == null) {
57+
CompilerDirectives.transferToInterpreterAndInvalidate();
58+
writeModuleDoc = insert(WriteGlobalNode.create(__DOC__));
59+
}
60+
return writeModuleDoc;
61+
}
62+
4863
@Override
4964
public Object execute(VirtualFrame frame) {
5065
addClosureCellsToLocals(frame);
66+
if (doc != null) {
67+
getWriteModuleDoc().doWrite(frame, doc);
68+
}
5169
return body.execute(frame);
5270
}
5371

@@ -66,6 +84,10 @@ public String getName() {
6684
return name;
6785
}
6886

87+
public String getDoc() {
88+
return doc;
89+
}
90+
6991
@Override
7092
public SourceSection getSourceSection() {
7193
return body.getSourceSection();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ public <T> T duplicate(Node orig, Class<T> clazz) {
132132
return (T) NodeUtil.cloneNode(orig);
133133
}
134134

135-
public ModuleRootNode createModuleRoot(String name, ExpressionNode file, FrameDescriptor fd) {
135+
public ModuleRootNode createModuleRoot(String name, String doc, ExpressionNode file, FrameDescriptor fd) {
136136
file.markAsRoot();
137-
return new ModuleRootNode(language, name, file, fd, null);
137+
return new ModuleRootNode(language, name, doc, file, fd, null);
138138
}
139139

140140
public FunctionRootNode createFunctionRoot(SourceSection sourceSection, String functionName, boolean isGenerator, FrameDescriptor frameDescriptor, ExpressionNode body,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonTreeTranslator.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public Object visitFile_input(Python3Parser.File_inputContext ctx) {
232232
ExpressionNode file = asExpression(super.visitFile_input(ctx));
233233
deriveSourceSection(ctx, file);
234234
environment.popScope();
235-
return factory.createModuleRoot(name, file, ctx.scope.getFrameDescriptor());
235+
return factory.createModuleRoot(name, getModuleDoc(ctx), file, ctx.scope.getFrameDescriptor());
236236
}
237237

238238
@Override
@@ -256,10 +256,34 @@ public Object visitSingle_input(Python3Parser.Single_inputContext ctx) {
256256
if (isInlineMode) {
257257
return body;
258258
} else {
259-
return factory.createModuleRoot("<expression>", body, ctx.scope.getFrameDescriptor());
259+
return factory.createModuleRoot("<expression>", getModuleDoc(ctx), body, ctx.scope.getFrameDescriptor());
260260
}
261261
}
262262

263+
private String getModuleDoc(ParserRuleContext ctx) {
264+
Python3Parser.Simple_stmtContext firstStatement = null;
265+
if (ctx instanceof Python3Parser.Single_inputContext) {
266+
firstStatement = ((Python3Parser.Single_inputContext) ctx).simple_stmt();
267+
} else if (ctx instanceof Python3Parser.File_inputContext) {
268+
List<Python3Parser.StmtContext> stmt = ((Python3Parser.File_inputContext) ctx).stmt();
269+
if (!stmt.isEmpty()) {
270+
firstStatement = stmt.get(0).simple_stmt();
271+
}
272+
}
273+
274+
if (firstStatement != null) {
275+
try {
276+
PNode stringNode = parseString(new String[]{firstStatement.getText().trim()});
277+
if (stringNode instanceof StringLiteralNode) {
278+
return ((StringLiteralNode) stringNode).getValue();
279+
}
280+
} catch (Exception ignored) {
281+
// not a string literal
282+
}
283+
}
284+
return null;
285+
}
286+
263287
@Override
264288
public Object visitAtom_expr(Python3Parser.Atom_exprContext ctx) {
265289
// TODO: deal with AWAIT

0 commit comments

Comments
 (0)