mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
[pycharm] PY-72340 Jupyter(feat): Support "File <file>:<line>" format for highlight of stacktraces, resolve path with ~
GitOrigin-RevId: 8ba99b238db19eaf1cf714df2ac388a649a61d88
This commit is contained in:
committed by
intellij-monorepo-bot
parent
204288e1fa
commit
7032ef2e1c
@@ -1,32 +1,36 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.run;
|
||||
package com.jetbrains.python.run
|
||||
|
||||
import com.jetbrains.python.traceBackParsers.LinkInTrace;
|
||||
import com.jetbrains.python.traceBackParsers.TraceBackParserAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import com.jetbrains.python.traceBackParsers.LinkInTrace
|
||||
import com.jetbrains.python.traceBackParsers.TraceBackParserAdapter
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* Finds links in default python traceback
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
public class PyTracebackParser extends TraceBackParserAdapter {
|
||||
open class PyTracebackParser : TraceBackParserAdapter(Pattern.compile(
|
||||
"(File \"(?<file>[^0-9][^\"]{0,200})\", line (?<line>\\d{1,8}))|(File (?<file2>[^0-9][^\"]{0,200}):(?<line2>\\d{1,8}))")) {
|
||||
override fun findLinkInTrace(line: String, matchedMatcher: Matcher): LinkInTrace {
|
||||
val file1 = matchedMatcher.group("file")
|
||||
val file2 = matchedMatcher.group("file2")
|
||||
val fileName = (file1 ?: file2).replace('\\', '/')
|
||||
|
||||
val lineNumber1 = matchedMatcher.group("line")
|
||||
val lineNumber2 = matchedMatcher.group("line2")
|
||||
val lineNumber = (lineNumber1 ?: lineNumber2).toInt()
|
||||
|
||||
public PyTracebackParser() {
|
||||
// File name can't start with number, can't be more then 200 chars long (its insane) and line number is also limited to int maxvalue
|
||||
super(Pattern.compile("File \"([^0-9][^\"]{0,200})\", line (\\d{1,8})"));
|
||||
if (file1 != null && lineNumber1 != null) {
|
||||
val startPos = line.indexOf('\"') + 1
|
||||
val endPos = line.indexOf('\"', startPos)
|
||||
return LinkInTrace(fileName, lineNumber, startPos, endPos)
|
||||
}
|
||||
else {
|
||||
val startPos = matchedMatcher.start("file2")
|
||||
val endPos = matchedMatcher.end("line2")
|
||||
return LinkInTrace(fileName, lineNumber, startPos, endPos)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull LinkInTrace findLinkInTrace(final @NotNull String line, final @NotNull Matcher matchedMatcher) {
|
||||
final String fileName = matchedMatcher.group(1).replace('\\', '/');
|
||||
final int lineNumber = Integer.parseInt(matchedMatcher.group(2));
|
||||
final int startPos = line.indexOf('\"') + 1;
|
||||
final int endPos = line.indexOf('\"', startPos);
|
||||
return new LinkInTrace(fileName, lineNumber, startPos, endPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.run;
|
||||
|
||||
import com.intellij.execution.filters.Filter;
|
||||
import com.intellij.execution.filters.OpenFileHyperlinkInfo;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.python.traceBackParsers.LinkInTrace;
|
||||
import com.jetbrains.python.traceBackParsers.TraceBackParser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public class PythonTracebackFilter implements Filter {
|
||||
private final Project myProject;
|
||||
private final String myWorkingDirectory;
|
||||
|
||||
public PythonTracebackFilter(final Project project) {
|
||||
myProject = project;
|
||||
myWorkingDirectory = project.getBasePath();
|
||||
}
|
||||
|
||||
public PythonTracebackFilter(final Project project, final @Nullable String workingDirectory) {
|
||||
myProject = project;
|
||||
myWorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable Result applyFilter(final @NotNull String line, final int entireLength) {
|
||||
|
||||
for (final TraceBackParser parser : TraceBackParser.PARSERS) {
|
||||
final LinkInTrace linkInTrace = parser.findLinkInTrace(line);
|
||||
if (linkInTrace == null) {
|
||||
continue;
|
||||
}
|
||||
final int lineNumber = linkInTrace.getLineNumber();
|
||||
final VirtualFile vFile = findFileByName(linkInTrace.getFileName());
|
||||
|
||||
if (vFile != null) {
|
||||
if (!vFile.isDirectory()) {
|
||||
var extension = vFile.getExtension();
|
||||
if (extension != null && !extension.equals("py")) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
final OpenFileHyperlinkInfo hyperlink = new OpenFileHyperlinkInfo(myProject, vFile, lineNumber - 1);
|
||||
final int textStartOffset = entireLength - line.length();
|
||||
final int startPos = linkInTrace.getStartPos();
|
||||
final int endPos = linkInTrace.getEndPos();
|
||||
return new Result(startPos + textStartOffset, endPos + textStartOffset, hyperlink);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected @Nullable VirtualFile findFileByName(final @NotNull String fileName) {
|
||||
VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fileName);
|
||||
if (vFile == null && !StringUtil.isEmptyOrSpaces(myWorkingDirectory)) {
|
||||
vFile = LocalFileSystem.getInstance().findFileByIoFile(new File(myWorkingDirectory, fileName));
|
||||
}
|
||||
return vFile;
|
||||
}
|
||||
|
||||
protected Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
}
|
||||
66
python/src/com/jetbrains/python/run/PythonTracebackFilter.kt
Normal file
66
python/src/com/jetbrains/python/run/PythonTracebackFilter.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.run
|
||||
|
||||
import com.intellij.execution.filters.Filter
|
||||
import com.intellij.execution.filters.OpenFileHyperlinkInfo
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.SystemProperties
|
||||
import com.jetbrains.python.traceBackParsers.TraceBackParser
|
||||
import java.io.File
|
||||
|
||||
open class PythonTracebackFilter : Filter {
|
||||
protected val project: Project
|
||||
private val myWorkingDirectory: String?
|
||||
|
||||
constructor(project: Project) {
|
||||
this.project = project
|
||||
myWorkingDirectory = project.basePath
|
||||
}
|
||||
|
||||
constructor(project: Project, workingDirectory: String?) {
|
||||
this.project = project
|
||||
myWorkingDirectory = workingDirectory
|
||||
}
|
||||
|
||||
override fun applyFilter(line: String, entireLength: Int): Filter.Result? {
|
||||
for (parser in TraceBackParser.PARSERS) {
|
||||
val linkInTrace = parser.findLinkInTrace(line)
|
||||
if (linkInTrace == null) {
|
||||
continue
|
||||
}
|
||||
val lineNumber = linkInTrace.lineNumber
|
||||
val vFile = findFileByName(linkInTrace.fileName)
|
||||
|
||||
if (vFile != null) {
|
||||
if (!vFile.isDirectory) {
|
||||
val extension = vFile.extension
|
||||
if (extension != null && extension != "py") {
|
||||
return null
|
||||
}
|
||||
}
|
||||
val hyperlink = OpenFileHyperlinkInfo(project, vFile, lineNumber - 1)
|
||||
val textStartOffset = entireLength - line.length
|
||||
val startPos = linkInTrace.startPos
|
||||
val endPos = linkInTrace.endPos
|
||||
return Filter.Result(startPos + textStartOffset, endPos + textStartOffset, hyperlink)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
protected open fun findFileByName(fileName: String): VirtualFile? {
|
||||
val preparedName = if (fileName.startsWith("~")) {
|
||||
fileName.replaceFirst("~".toRegex(), SystemProperties.getUserHome())
|
||||
}
|
||||
else {
|
||||
fileName
|
||||
}
|
||||
var vFile = LocalFileSystem.getInstance().findFileByPath(preparedName)
|
||||
if (vFile == null && !myWorkingDirectory.isNullOrBlank()) {
|
||||
vFile = LocalFileSystem.getInstance().findFileByIoFile(File(myWorkingDirectory, preparedName))
|
||||
}
|
||||
return vFile
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,16 @@ public class PyTracebackParserTest extends TestCase {
|
||||
Assert.assertEquals("Bad end pos", 16, linkInTrace.getEndPos());
|
||||
}
|
||||
|
||||
public void testLineWithLink2() {
|
||||
final LinkInTrace linkInTrace = new PyTracebackParser().findLinkInTrace(
|
||||
"File ~/.pyenv/versions/3.10.11/lib/python3.10/threading.py:324, in Condition.wait(self, timeout)");
|
||||
Assert.assertNotNull("Failed to parse line", linkInTrace);
|
||||
Assert.assertEquals("Bad file name", "~/.pyenv/versions/3.10.11/lib/python3.10/threading.py", linkInTrace.getFileName());
|
||||
Assert.assertEquals("Bad line number", 324, linkInTrace.getLineNumber());
|
||||
Assert.assertEquals("Bad start pos", 5, linkInTrace.getStartPos());
|
||||
Assert.assertEquals("Bad end pos", 62, linkInTrace.getEndPos());
|
||||
}
|
||||
|
||||
/**
|
||||
* lines with out of file references should not have links
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user