Skip to content

Commit 04d3301

Browse files
committed
provide full _warnings API, but warn and warn_explicit only as wrappers around the python impls
1 parent 692bb88 commit 04d3301

7 files changed

Lines changed: 309 additions & 54 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
import com.oracle.graal.python.builtins.modules.TimeModuleBuiltins;
9898
import com.oracle.graal.python.builtins.modules.TraceModuleBuiltins;
9999
import com.oracle.graal.python.builtins.modules.UnicodeDataModuleBuiltins;
100+
import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins;
100101
import com.oracle.graal.python.builtins.modules.WeakRefModuleBuiltins;
101102
import com.oracle.graal.python.builtins.modules.ZLibModuleBuiltins;
102103
import com.oracle.graal.python.builtins.modules.ZipImportModuleBuiltins;
@@ -228,7 +229,6 @@ private static String[] initializeCoreFiles() {
228229
"_functools",
229230
"method",
230231
"code",
231-
"_warnings",
232232
"posix",
233233
"_io",
234234
"_frozen_importlib",
@@ -422,6 +422,7 @@ private static PythonBuiltins[] initializeBuiltins() {
422422
new LZMADecompressorBuiltins(),
423423
new MultiprocessingModuleBuiltins(),
424424
new SemLockBuiltins(),
425+
new WarningsModuleBuiltins(),
425426
new GraalPythonModuleBuiltins()));
426427
if (hasCoverageTool) {
427428
builtins.add(new TraceModuleBuiltins());
@@ -636,7 +637,6 @@ private void populateBuiltins() {
636637

637638
// core machinery
638639
createModule("_descriptor");
639-
createModule("_warnings");
640640
PythonModule bootstrapExternal = createModule("importlib._bootstrap_external");
641641
bootstrapExternal.setAttribute(__PACKAGE__, "importlib");
642642
builtinModules.put("_frozen_importlib_external", bootstrapExternal);
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.modules;
42+
43+
import java.util.List;
44+
45+
import com.oracle.graal.python.PythonLanguage;
46+
import com.oracle.graal.python.builtins.Builtin;
47+
import com.oracle.graal.python.builtins.CoreFunctions;
48+
import com.oracle.graal.python.builtins.PythonBuiltins;
49+
import com.oracle.graal.python.builtins.objects.PNone;
50+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
51+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
52+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
53+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromDynamicObjectNode;
54+
import com.oracle.graal.python.nodes.attributes.WriteAttributeToDynamicObjectNode;
55+
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
56+
import com.oracle.graal.python.nodes.call.CallNode;
57+
import com.oracle.graal.python.nodes.expression.ExpressionNode;
58+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
59+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
60+
import com.oracle.graal.python.nodes.statement.ImportNode;
61+
import com.oracle.graal.python.runtime.PythonCore;
62+
import com.oracle.graal.python.runtime.PythonOptions;
63+
import com.oracle.graal.python.runtime.formatting.ErrorMessageFormatter;
64+
import com.oracle.truffle.api.Assumption;
65+
import com.oracle.truffle.api.CompilerDirectives;
66+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
67+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
68+
import com.oracle.truffle.api.TruffleLogger;
69+
import com.oracle.truffle.api.dsl.Cached;
70+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
71+
import com.oracle.truffle.api.dsl.NodeFactory;
72+
import com.oracle.truffle.api.dsl.Specialization;
73+
import com.oracle.truffle.api.frame.VirtualFrame;
74+
import com.oracle.truffle.api.interop.InteropLibrary;
75+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
76+
import com.oracle.truffle.api.object.DynamicObject;
77+
import com.oracle.truffle.api.object.HiddenKey;
78+
import com.oracle.truffle.api.profiles.BranchProfile;
79+
80+
@CoreFunctions(defineModule = "_warnings")
81+
public class WarningsModuleBuiltins extends PythonBuiltins {
82+
private static final TruffleLogger LOGGER = PythonLanguage.getLogger(WarningsModuleBuiltins.class);
83+
84+
@Override
85+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
86+
return WarningsModuleBuiltinsFactory.getFactories();
87+
}
88+
89+
private static final HiddenKey FILTERS_MUTATED = new HiddenKey("filtersMutated");
90+
private static final HiddenKey PYTHON_WARN = new HiddenKey("warn");
91+
private static final HiddenKey PYTHON_WARN_EXPLICIT = new HiddenKey("warn_explicit");
92+
private static final HiddenKey PYTHON_WARNINGS = new HiddenKey("warnings");
93+
94+
@Override
95+
public void initialize(PythonCore core) {
96+
builtinConstants.put(SpecialAttributeNames.__DOC__, "_warnings provides basic warning filtering support.\n" +
97+
"It is a helper module to speed up interpreter start-up.");
98+
builtinConstants.put("filters", core.factory().createList());
99+
builtinConstants.put("_defaultaction", "ignore");
100+
builtinConstants.put("_onceregistry", core.factory().createDict());
101+
super.initialize(core);
102+
}
103+
104+
@Override
105+
public void postInitialize(PythonCore core) {
106+
super.postInitialize(core);
107+
PythonModule weakrefModule = core.lookupBuiltinModule("_warnings");
108+
if (core.getContext().getOption(PythonOptions.WarnOptions).equals("ignore")) {
109+
weakrefModule.setAttribute(FILTERS_MUTATED, -1);
110+
} else {
111+
weakrefModule.setAttribute(FILTERS_MUTATED, 0);
112+
}
113+
}
114+
115+
protected static boolean ignoreWarnings(PythonModule mod, ReadAttributeFromDynamicObjectNode readState) {
116+
return ((int) readState.execute(mod.getStorage(), FILTERS_MUTATED)) < 0;
117+
}
118+
119+
protected static Object getOrDefault(Object obj) {
120+
return getOrDefault(obj, PNone.NONE);
121+
}
122+
123+
protected static Object getOrDefault(Object obj, Object def) {
124+
if (obj == PNone.NO_VALUE) {
125+
return def;
126+
} else {
127+
return obj;
128+
}
129+
}
130+
131+
@Builtin(name = "_register_python_warnings", minNumOfPositionalArgs = 4, declaresExplicitSelf = true)
132+
@GenerateNodeFactory
133+
static abstract class RegisterNode extends PythonBuiltinNode {
134+
@Specialization
135+
static Object mutate(PythonModule mod,
136+
Object warnMethod,
137+
Object warnExplicitMethod,
138+
PythonModule warningsModule,
139+
@Cached WriteAttributeToDynamicObjectNode writeNode) {
140+
DynamicObject storage = mod.getStorage();
141+
writeNode.execute(storage, PYTHON_WARN, warnMethod);
142+
writeNode.execute(storage, PYTHON_WARN_EXPLICIT, warnExplicitMethod);
143+
writeNode.execute(storage, PYTHON_WARNINGS, warningsModule);
144+
return PNone.NONE;
145+
}
146+
}
147+
148+
@Builtin(name = "_filters_mutated", minNumOfPositionalArgs = 1, declaresExplicitSelf = true)
149+
@GenerateNodeFactory
150+
static abstract class FiltersMutated extends PythonBuiltinNode {
151+
@Specialization
152+
static Object mutate(PythonModule mod,
153+
@Cached ReadAttributeFromDynamicObjectNode readWarningsNode,
154+
@Cached WriteAttributeToObjectNode writeWarningsFiltersVersion,
155+
@Cached ReadAttributeFromDynamicObjectNode readNode,
156+
@Cached WriteAttributeToDynamicObjectNode writeNode) {
157+
int version = (int) readNode.execute(mod.getStorage(), FILTERS_MUTATED);
158+
writeNode.execute(mod.getStorage(), FILTERS_MUTATED, version + 1);
159+
Object warnMod = readWarningsNode.execute(mod.getStorage(),PYTHON_WARNINGS);
160+
if (warnMod != PNone.NO_VALUE) {
161+
writeWarningsFiltersVersion.execute(warnMod, "_filters_version", version);
162+
}
163+
return version;
164+
}
165+
}
166+
167+
@TruffleBoundary
168+
private static final String formatWarning(Object message, Object category, Object filename, Object lineno) {
169+
InteropLibrary lib = InteropLibrary.getUncached();
170+
StringBuilder sb = new StringBuilder();
171+
try {
172+
if (filename != null) {
173+
sb.append(lib.asString(lib.toDisplayString(filename))).append(":");
174+
}
175+
if (lineno != null) {
176+
sb.append(lib.asString(lib.toDisplayString(lineno))).append(": ");
177+
}
178+
if (category != null && !(category instanceof PNone)) {
179+
sb.append(lib.asString(lib.toDisplayString(category))).append(":");
180+
} else {
181+
sb.append("UserWarning: ");
182+
}
183+
sb.append(lib.asString(lib.toDisplayString(message)));
184+
return sb.toString();
185+
} catch (UnsupportedMessageException e) {
186+
throw CompilerDirectives.shouldNotReachHere(e);
187+
}
188+
}
189+
190+
@Builtin(name = "warn_explicit", parameterNames = {"mod", "message", "category", "filename", "lineno", "module", "registry", "module_globals", "source"},
191+
declaresExplicitSelf = true, minNumOfPositionalArgs = 5)
192+
@GenerateNodeFactory
193+
static abstract class WarnExplicitNode extends PythonBuiltinNode {
194+
protected static ExpressionNode getImportNode() {
195+
return new ImportNode("warnings").asExpression();
196+
}
197+
198+
@Specialization
199+
Object warn(VirtualFrame frame, PythonModule mod, Object message, Object category, Object filename, Object lineno, Object module, Object registry, Object moduleGlobals, Object source,
200+
@Cached BranchProfile noLogger,
201+
@Cached ReadAttributeFromDynamicObjectNode readState,
202+
@Cached ReadAttributeFromDynamicObjectNode readWarn,
203+
@Cached CallNode callNode) {
204+
if (ignoreWarnings(mod, readState)) {
205+
return PNone.NONE;
206+
}
207+
Object method = readWarn.execute(mod.getStorage(), PYTHON_WARN_EXPLICIT);
208+
if (method == PNone.NO_VALUE) {
209+
noLogger.enter();
210+
LOGGER.warning(() -> formatWarning(message, category, filename, lineno));
211+
return PNone.NONE;
212+
}
213+
return callNode.execute(frame, method, message, category, filename, lineno, getOrDefault(module), getOrDefault(registry), getOrDefault(moduleGlobals), getOrDefault(source));
214+
}
215+
}
216+
217+
/**
218+
* Can be used as equivalent for PyErr_WarnFormat.
219+
*/
220+
@Builtin(name = "warn", parameterNames = {"mod", "message", "category", "stacklevel", "source"}, declaresExplicitSelf = true, minNumOfPositionalArgs = 2)
221+
@GenerateNodeFactory
222+
public static abstract class WarnNode extends PythonBuiltinNode {
223+
private final BranchProfile noLogger = BranchProfile.create();
224+
@CompilationFinal private Assumption singleContextAssumption;
225+
@CompilationFinal private PythonModule builtinMod;
226+
@CompilationFinal private ErrorMessageFormatter formatter;
227+
228+
@Child private ReadAttributeFromDynamicObjectNode readWarn;
229+
@Child private ReadAttributeFromDynamicObjectNode readState;
230+
@Child private CallNode callNode;
231+
232+
// an optimization to avoid formatting the message string if we know that warnings are disabled
233+
public final Object execute(VirtualFrame frame, Object category, String message, Object... arguments) {
234+
PythonModule warningsMod;
235+
if (getSingleContextAssumption().isValid()) {
236+
if (builtinMod == null) {
237+
CompilerDirectives.transferToInterpreterAndInvalidate();
238+
builtinMod = getContext().getCore().lookupBuiltinModule("_warnings");
239+
}
240+
warningsMod = builtinMod;
241+
} else {
242+
warningsMod = getContext().getCore().lookupBuiltinModule("_warnings");
243+
}
244+
if (ignoreWarnings(warningsMod, getReadState())) {
245+
return PNone.NONE;
246+
}
247+
if (formatter == null) { // acts as branch profile
248+
formatter = new ErrorMessageFormatter();
249+
}
250+
return warn(frame, warningsMod, formatter.format(PythonObjectLibrary.getUncached(), message, arguments), category, 1, PNone.NONE);
251+
}
252+
253+
@Specialization
254+
Object warn(VirtualFrame frame, PythonModule mod, Object message, Object wCategory, Object wStacklevel, Object source) {
255+
if (ignoreWarnings(mod, getReadState())) {
256+
return PNone.NONE;
257+
}
258+
Object method = getReadWarn().execute(mod.getStorage(), PYTHON_WARN);
259+
if (method == PNone.NO_VALUE) {
260+
noLogger.enter();
261+
LOGGER.warning(() -> formatWarning(message, wCategory, null, null));
262+
return PNone.NONE;
263+
}
264+
return getCallNode().execute(frame, method, message, getOrDefault(wCategory), getOrDefault(wStacklevel, 1), getOrDefault(source));
265+
}
266+
267+
private Assumption getSingleContextAssumption() {
268+
if (singleContextAssumption == null) {
269+
CompilerDirectives.transferToInterpreterAndInvalidate();
270+
singleContextAssumption = singleContextAssumption();
271+
}
272+
return singleContextAssumption;
273+
}
274+
275+
private ReadAttributeFromDynamicObjectNode getReadWarn() {
276+
if (readWarn == null) {
277+
CompilerDirectives.transferToInterpreterAndInvalidate();
278+
readWarn = insert(ReadAttributeFromDynamicObjectNode.create());
279+
}
280+
return readWarn;
281+
}
282+
283+
private ReadAttributeFromDynamicObjectNode getReadState() {
284+
if (readState == null) {
285+
CompilerDirectives.transferToInterpreterAndInvalidate();
286+
readState = insert(ReadAttributeFromDynamicObjectNode.create());
287+
}
288+
return readState;
289+
}
290+
291+
private CallNode getCallNode() {
292+
if (callNode == null) {
293+
CompilerDirectives.transferToInterpreterAndInvalidate();
294+
callNode = insert(CallNode.create());
295+
}
296+
return callNode;
297+
}
298+
}
299+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public Object execute(VirtualFrame frame) {
6161

6262
}
6363

64-
public ExpressionNode asExpression() {
64+
public ImportExpression asExpression() {
6565
return new ImportExpression(this);
6666
}
6767

graalpython/lib-graalpython/_io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2323
# DEALINGS IN THE SOFTWARE.
2424
import sys
25-
_warn = sys.modules["_warnings"]._warn
25+
_warn = sys.modules["_warnings"].warn
2626
_os = sys.modules.get("posix", sys.modules.get("nt"))
2727

2828

graalpython/lib-graalpython/_warnings.py

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)