github.com/xyproto/orbiton/v2@v2.65.12-0.20240516144430-e10a419274ec/pyparserr.go (about) 1 package main 2 3 import ( 4 "strconv" 5 "strings" 6 ) 7 8 // ParsePythonError parses a Python error message and returns the line number and first error message. 9 // If no error message is found, -1 and an empty string will be returned. 10 func ParsePythonError(msg, filename string) (int, int, string) { 11 var ( 12 foundLineNumber bool // ... ", line N" 13 foundHat bool // ^ 14 errorMessage string // Typically after "SyntaxError: " 15 lineNumber = -1 // The line number with the Python error, if any 16 columnNumber = -1 // The column number, from the position of the "^" in the error message, if any 17 err error // Only used within the loop below 18 ) 19 for _, line := range strings.Split(msg, "\n") { 20 if foundHat && strings.Contains(line, ": ") { 21 errorMessage = strings.SplitN(line, ": ", 2)[1] 22 // break since this is usually the end of the approximately 5 line error message from Python 23 break 24 } else if foundLineNumber && len(line) > 4 { 25 // de-indent the line before finding the hat column number 26 if hatPos := strings.Index(line[4:], "^"); hatPos != -1 { 27 foundHat = true 28 // this is the column number (not index), 29 columnNumber = hatPos + 1 30 } else { 31 continue 32 } 33 } else if strippedLine := strings.TrimSpace(line); strings.Contains(line, "\""+filename+"\"") || (strings.HasPrefix(strippedLine, "File ") && strings.Contains(line, "\", line ")) { 34 fields := strings.Split(strippedLine, ", line ") 35 if len(fields) < 2 { 36 continue 37 } 38 lineNumber, err = strconv.Atoi(fields[1]) 39 if err != nil { 40 continue 41 } 42 foundLineNumber = true 43 } else if strippedLine := strings.TrimSpace(line); strings.Contains(line, "("+filename+", ") && strings.Contains(line, "Error: ") { 44 fields := strings.SplitN(strippedLine, "Error: ", 2) 45 errorMessageFileAndLine := fields[1] 46 fields = strings.SplitN(errorMessageFileAndLine, "("+filename+", ", 2) 47 errorMessage = fields[0] 48 lineNumberString := fields[1] 49 lineNumberString = strings.TrimPrefix(lineNumberString, "line ") 50 lineNumberString = strings.TrimSuffix(lineNumberString, ")") 51 if n, err := strconv.Atoi(lineNumberString); err == nil { 52 lineNumber = n 53 } 54 } 55 } 56 57 // Strip the "(detected at line N)" message at the end 58 if strings.HasSuffix(errorMessage, ")") && strings.Contains(errorMessage, "(detected at line ") { 59 fields := strings.SplitN(errorMessage, "(detected at line ", 2) 60 errorMessage = strings.TrimSpace(fields[0]) 61 } 62 63 return lineNumber, columnNumber, errorMessage 64 }