Skip to content

Commit 11be90e

Browse files
committed
Added new mypy type checking
1 parent bb8f7bb commit 11be90e

File tree

3 files changed

+66
-25
lines changed

3 files changed

+66
-25
lines changed

utbot-python/samples/easy_samples/annotation_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class A(Generic[XXX]):
1212

1313
def f(self, a, b: A[int]):
1414
self.y = b
15-
self_.x = b
15+
self.self_.x = b
1616
pass
1717

1818
def g(self):

utbot-python/src/main/kotlin/org/utbot/python/newtyping/PythonType.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ sealed class PythonTypeDescription(name: Name) : TypeMetaDataWithName(name) {
8181
open fun createTypeWithNewAnnotationParameters(like: Type, newParams: List<Type>): Type = // overriden for Callable
8282
DefaultSubstitutionProvider.substituteAll(like.getOrigin(), newParams)
8383
open fun getTypeRepresentation(type: Type): String { // overriden for Callable
84-
val root = name.prefix.joinToString() + "." + name.name
84+
val root =
85+
if (name.prefix.isEmpty())
86+
name.name
87+
else
88+
name.prefix.joinToString() + "." + name.name
89+
8590
val params = getAnnotationParameters(type)
8691
if (params.isEmpty())
8792
return root

utbot-python/src/main/kotlin/org/utbot/python/newtyping/runmypy/RunMypy.kt

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fun readMypyAnnotationStorageAndInitialErrors(
1515
pythonPath: String,
1616
sourcePath: String,
1717
configFile: File
18-
): Pair<MypyAnnotationStorage, String> {
18+
): Pair<MypyAnnotationStorage, List<MypyReportLine>> {
1919
val fileForAnnotationStorage = TemporaryFileManager.assignTemporaryFile(tag = "annotations.json")
2020
val fileForMypyStdout = TemporaryFileManager.assignTemporaryFile(tag = "mypy.out")
2121
val fileForMypyStderr = TemporaryFileManager.assignTemporaryFile(tag = "mypy.err")
@@ -41,7 +41,7 @@ fun readMypyAnnotationStorageAndInitialErrors(
4141
error("Something went wrong in initial mypy run. Stderr: $stderr")
4242
return Pair(
4343
readMypyAnnotationStorage(fileForAnnotationStorage.readText()),
44-
fileForMypyStdout.readText()
44+
getErrorsAndNotes(fileForMypyStdout.readText())
4545
)
4646
}
4747

@@ -61,12 +61,11 @@ fun checkWithDMypy(pythonPath: String, fileWithCodePath: String, configFile: Fil
6161
return result.stdout
6262
}
6363

64-
private const val configFilename = "config.ini"
65-
66-
private fun setConfigFile(): File {
64+
private fun setConfigFile(directoriesForSysPath: Set<String>): File {
6765
val file = TemporaryFileManager.assignTemporaryFile(configFilename)
6866
val configContent = """
6967
[mypy]
68+
mypy_path = ${directoriesForSysPath.joinToString(separator = ":")}
7069
namespace_packages = True
7170
explicit_package_bases = True
7271
show_absolute_path = True
@@ -79,30 +78,59 @@ private fun setConfigFile(): File {
7978
fun checkSuggestedSignatureWithDMypy(
8079
method: PythonMethod,
8180
directoriesForSysPath: Set<String>,
82-
moduleToImport: String
83-
): String {
81+
moduleToImport: String,
82+
fileForMypyCode: File,
83+
pythonPath: String,
84+
configFile: File,
85+
initialErrorNumber: Int
86+
): Boolean {
8487
val description = method.type.pythonDescription() as PythonCallableTypeDescription
8588
val annotationMap =
8689
(description.argumentNames zip method.type.arguments.map { it.pythonTypeRepresentation() }).associate {
8790
Pair(it.first, NormalizedPythonAnnotation(it.second))
8891
}
8992
val mypyCode = generateMypyCheckCode(method, annotationMap, directoriesForSysPath, moduleToImport)
90-
return mypyCode
93+
TemporaryFileManager.writeToAssignedFile(fileForMypyCode, mypyCode)
94+
val mypyOutput = checkWithDMypy(pythonPath, fileForMypyCode.canonicalPath, configFile)
95+
val report = getErrorsAndNotes(mypyOutput)
96+
val errorNumber = getErrorNumber(report, fileForMypyCode.canonicalPath, 0, mypyCode.length)
97+
return errorNumber <= initialErrorNumber
98+
}
99+
100+
private const val configFilename = "config.ini"
101+
102+
data class MypyReportLine(
103+
val line: Int,
104+
val type: String,
105+
val message: String,
106+
val file: String
107+
)
108+
109+
private fun getErrorNumber(mypyReport: List<MypyReportLine>, filename: String, startLine: Int, endLine: Int) =
110+
mypyReport.count { it.type == "error" && it.file == filename && it.line >= startLine && it.line <= endLine }
111+
112+
private fun getErrorsAndNotes(mypyOutput: String): List<MypyReportLine> {
113+
val regex = Regex("(?m)^([^\n]*):([0-9]*): (error|note): ([^\n]*)\n")
114+
return regex.findAll(mypyOutput).toList().map { match ->
115+
val file = match.groupValues[1]
116+
MypyReportLine(
117+
match.groupValues[2].toInt(),
118+
match.groupValues[3],
119+
match.groupValues[4],
120+
file
121+
)
122+
}
91123
}
92124

93125
fun main() {
94126
TemporaryFileManager.setup()
95-
val configFile = setConfigFile()
96-
val filePath = "/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples/easy_samples/annotation_tests.py"
127+
val sysPath = setOf("/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples/easy_samples")
128+
val configFile = setConfigFile(sysPath)
129+
val filePath =
130+
"/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples/easy_samples/annotation_tests.py"
97131
val (storage, mypyOut) = readMypyAnnotationStorageAndInitialErrors("python3", filePath, configFile)
98-
println(mypyOut)
99-
println(
100-
checkWithDMypy(
101-
"python3",
102-
filePath,
103-
configFile
104-
)
105-
)
132+
val initialErrorNumber = getErrorNumber(mypyOut, filePath, 33, 34)
133+
println(initialErrorNumber)
106134
val type = storage.definitions["annotation_tests"]!!["same_annotations"]!!.annotation.asUtBotType as FunctionType
107135
val pythonMethod = PythonMethod(
108136
"same_annotations",
@@ -112,13 +140,21 @@ fun main() {
112140
},
113141
filePath,
114142
null,
115-
"result = set()\n" +
116-
"for elem in collection:\n" +
117-
" result.add(elem ** 2)\n" +
118-
"return result\n"
143+
"return x + y"
119144
)
120145
pythonMethod.type = type
121-
println(checkSuggestedSignatureWithDMypy(pythonMethod, emptySet(), "annotation_tests"))
146+
val fileForMypyCode = TemporaryFileManager.assignTemporaryFile(tag = "mypy.py")
147+
println(
148+
checkSuggestedSignatureWithDMypy(
149+
pythonMethod,
150+
sysPath,
151+
"annotation_tests",
152+
fileForMypyCode,
153+
"python3",
154+
configFile,
155+
initialErrorNumber
156+
)
157+
)
122158

123159
Cleaner.doCleaning()
124160
}

0 commit comments

Comments
 (0)