Skip to content

Commit dabe4af

Browse files
committed
Merge branch 'utbot-python' of github.com:UnitTestBot/UTBotJava into utbot-python
2 parents 7267193 + d706921 commit dabe4af

File tree

13 files changed

+200891
-331879
lines changed

13 files changed

+200891
-331879
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,48 @@ class PythonInitObjectModel(
283283
}
284284
}
285285

286+
data class PythonListModel(
287+
override val classId: ClassId,
288+
val length: Int = 0,
289+
val stores: List<UtModel>
290+
) : PythonModel(classId) {
291+
override fun toString() = withToStringThreadLocalReentrancyGuard {
292+
(0 until length).map { stores[it] }.joinToString(", ", "[", "]")
293+
}
294+
295+
companion object {
296+
val classId = ClassId("list")
297+
}
298+
}
299+
300+
data class PythonDictModel(
301+
override val classId: ClassId,
302+
val length: Int = 0,
303+
val stores: Map<PythonModel, PythonModel>
304+
) : PythonModel(classId) {
305+
override fun toString() = withToStringThreadLocalReentrancyGuard {
306+
stores.entries.joinToString(", ", "{", "}") { "${it.key}: ${it.value}" }
307+
}
308+
309+
companion object {
310+
val classId = ClassId("dict")
311+
}
312+
}
313+
314+
data class PythonSetModel(
315+
override val classId: ClassId,
316+
val length: Int = 0,
317+
val stores: Set<PythonModel>
318+
) : PythonModel(classId) {
319+
override fun toString() = withToStringThreadLocalReentrancyGuard {
320+
stores.joinToString(", ", "{", "}") { it.toString() }
321+
}
322+
323+
companion object {
324+
val classId = ClassId("set")
325+
}
326+
}
327+
286328
/**
287329
* Class representing models for values that might have an address.
288330
*

utbot-python/src/main/kotlin/org/utbot/python/PythonEngine.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,12 @@ class PythonEngine(
139139
): Sequence<Map<String, ClassId>> {
140140
val storageMap = argInfoCollector.getPriorityStorages()
141141
val userAnnotations = existingAnnotations.entries.associate {
142-
it.key to listOf(StubFileStructures.PythonInfoType(it.value))
142+
it.key to listOf(it.value)
143143
}
144144
val annotationCombinations = storageMap.entries.associate { (name, storages) ->
145145
name to storages.map { storage ->
146146
when (storage) {
147-
is ArgInfoCollector.TypeStorage -> setOf(StubFileStructures.PythonInfoType(storage.name))
147+
is ArgInfoCollector.TypeStorage -> setOf(storage.name)
148148
is ArgInfoCollector.MethodStorage -> StubFileFinder.findTypeWithMethod(storage.name)
149149
is ArgInfoCollector.FieldStorage -> StubFileFinder.findTypeWithField(storage.name)
150150
is ArgInfoCollector.FunctionArgStorage -> StubFileFinder.findTypeByFunctionWithArgumentPosition(
@@ -154,7 +154,7 @@ class PythonEngine(
154154
is ArgInfoCollector.FunctionRetStorage -> StubFileFinder.findTypeByFunctionReturnValue(
155155
storage.name
156156
)
157-
else -> setOf(StubFileStructures.PythonInfoType(storage.name))
157+
else -> setOf(storage.name)
158158
}
159159
}.flatten().toSet().toList()
160160
}

utbot-python/src/main/kotlin/org/utbot/python/code/CodeGen.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ object PythonCodeGenerator {
183183
private fun generateImportFunctionCode(
184184
functionPath: String,
185185
directoriesForSysPath: List<String>,
186-
additionalModules: List<StubFileStructures.PythonInfoType> = emptyList(),
186+
additionalModules: List<String> = emptyList(),
187187
): List<Statement> {
188188
val systemImport = Import(listOf(Alias("sys"), Alias("typing"), Alias("json")))
189189
val systemCalls = directoriesForSysPath.map { path ->
@@ -196,10 +196,13 @@ object PythonCodeGenerator {
196196
)
197197
)
198198
}
199-
val additionalImport = additionalModules.filter {
200-
it.module != ""
201-
}.map {
202-
ImportFrom(it.module, listOf(Alias(it.name)))
199+
val additionalImport = additionalModules.mapNotNull {
200+
if (it.contains(".")) {
201+
val module = it.split(".").dropLast(1).joinToString(".")
202+
Import(listOf(Alias(module)))
203+
} else {
204+
null
205+
}
203206
}
204207

205208
val mathImport = ImportFrom("math", listOf(Alias("*")))
@@ -293,7 +296,7 @@ object PythonCodeGenerator {
293296

294297
fun generateMypyCheckCode(
295298
method: PythonMethod,
296-
methodAnnotations: Map<String, StubFileStructures.PythonInfoType>,
299+
methodAnnotations: Map<String, String>,
297300
codeFilename: String,
298301
directoriesForSysPath: List<String>,
299302
moduleToImport: String
@@ -306,7 +309,7 @@ object PythonCodeGenerator {
306309

307310
val parameters = Parameters(
308311
method.arguments.map { argument ->
309-
Parameter("${argument.name}: ${methodAnnotations[argument.name]?.name ?: "typing.Any"}")
312+
Parameter("${argument.name}: ${methodAnnotations[argument.name] ?: "Any"}")
310313
},
311314
)
312315

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.utbot.python.providers
2+
3+
import org.utbot.framework.plugin.api.*
4+
import org.utbot.framework.plugin.api.util.voidClassId
5+
import org.utbot.fuzzer.*
6+
import kotlin.random.Random
7+
8+
object GenericModelProvider: ModelProvider {
9+
val concreteTypesModelProvider = ModelProvider.of(
10+
ConstantModelProvider,
11+
DefaultValuesModelProvider,
12+
GenericModelProvider
13+
)
14+
15+
override fun generate(description: FuzzedMethodDescription): Sequence<FuzzedParameter> = sequence {
16+
fun parseList(matchResult: MatchResult) = sequence {
17+
val genericType = matchResult.groupValues[0]
18+
val syntheticGenericType = FuzzedMethodDescription(
19+
"${description.name}<syntheticGenericList>",
20+
voidClassId,
21+
listOf(ClassId(genericType)),
22+
description.concreteValues
23+
)
24+
val models = fuzz(syntheticGenericType, concreteTypesModelProvider)
25+
.chunked(100) { list -> list.drop(Random.nextInt(list.size)) } // 100 is random max size
26+
.map { list ->
27+
PythonListModel(
28+
PythonListModel.classId,
29+
list.size,
30+
list.flatten().map { it.model },
31+
)
32+
}
33+
models.forEach {
34+
yield(FuzzedParameter(0, it.fuzzed()))
35+
}
36+
}
37+
38+
// fun parseDict(matchResult: MatchResult) = sequence {
39+
// TODO("NotImplementedError")
40+
// }
41+
//
42+
// fun parseSet(matchResult: MatchResult) = sequence {
43+
// TODO("NotImplementedError")
44+
// }
45+
46+
val modelRegexMap = mapOf<Regex, (MatchResult) -> Unit>(
47+
Regex(".*[Ll]ist\\[(.*)]}") to { matchResult -> parseList(matchResult) },
48+
Regex("typing.List\\[(.*)]}") to { matchResult -> parseList(matchResult) },
49+
// Regex(".*[Dd]ict\\[(.*)]}") to { matchResult -> parseDict(matchResult) },
50+
// Regex("typing.Dict\\[(.*)]}") to { matchResult -> parseDict(matchResult) },
51+
// Regex(".*[Ss]et\\[(.*)]}") to { matchResult -> parseSet(matchResult) },
52+
// Regex("typing.Set\\[(.*)]}") to { matchResult -> parseSet(matchResult) },
53+
)
54+
55+
// val generated = Array(description.parameters.size) { 0 }
56+
description.parametersMap.forEach { (classId, parameterIndices) ->
57+
val annotation = classId.name
58+
modelRegexMap.entries.forEach { (regex, action) ->
59+
val result = regex.matchEntire(annotation)
60+
if (result != null) {
61+
action(result)
62+
}
63+
}
64+
}
65+
}
66+
}
67+

utbot-python/src/main/kotlin/org/utbot/python/typing/MypyAnnotations.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import org.utbot.python.code.PythonCodeGenerator.generateMypyCheckCode
88
object MypyAnnotations {
99
fun mypyCheckAnnotations(
1010
method: PythonMethod,
11-
functionArgAnnotations: Map<String, List<StubFileStructures.PythonInfoType>>,
11+
functionArgAnnotations: Map<String, List<String>>,
1212
testSourcePath: String,
1313
moduleToImport: String,
1414
directoriesForSysPath: List<String>,
@@ -44,13 +44,8 @@ object MypyAnnotations {
4444
)
4545
val mypyOutput = runMypy(pythonPath, codeFilename, testSourcePath)
4646
if (mypyOutput == defaultOutput) {
47-
/*
48-
val goodTypes = listOf("str", "bool", "int", "float")
49-
if (annotationMap.values.all {x -> goodTypes.contains(x.name) } )
50-
yield(annotationMap)
51-
*/
5247
yield(annotationMap.mapValues { entry ->
53-
ClassId(entry.value.fullName)
48+
ClassId(entry.value)
5449
})
5550
}
5651
functionFile.deleteOnExit()

utbot-python/src/main/kotlin/org/utbot/python/typing/StubFileFinder.kt

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import com.beust.klaxon.Klaxon
44

55
object StubFileFinder {
66

7-
private val builtinMethods: List<StubFileStructures.MethodDatasetInfo>
8-
private val builtinFields: List<StubFileStructures.FieldDatasetInfo>
9-
private val builtinFunctions: List<StubFileStructures.FunctionDatasetInfo>
10-
private val builtinClasses: List<StubFileStructures.ClassDatasetInfo>
7+
private val builtinMethods: List<StubFileStructures.MethodIndex>
8+
private val builtinFields: List<StubFileStructures.FieldIndex>
9+
private val builtinFunctions: List<StubFileStructures.FunctionIndex>
10+
private val builtinClasses: List<StubFileStructures.ClassInfo>
1111

1212
init {
1313
val methodResource = StubFileFinder::class.java.getResourceAsStream("/method_annotations.json")
@@ -25,98 +25,91 @@ object StubFileFinder {
2525
builtinClasses = Klaxon().parseArray(classResource) ?: emptyList()
2626
}
2727

28-
val methodToTypeMap: Map<String, List<StubFileStructures.ClassMethodInfo>> by lazy {
29-
val result = mutableMapOf<String, List<StubFileStructures.ClassMethodInfo>>()
28+
val methodToTypeMap: Map<String, List<StubFileStructures.FunctionInfo>> by lazy {
29+
val result = mutableMapOf<String, List<StubFileStructures.FunctionInfo>>()
3030
builtinMethods.forEach { function ->
31-
result[function.name] = function.typeInfos
31+
result[function.name] = function.definitions
3232
}
3333
result
3434
}
3535

36-
val functionToAnnotationMap: Map<String, List<StubFileStructures.FunctionDefInfo>> by lazy {
37-
val result = mutableMapOf<String, List<StubFileStructures.FunctionDefInfo>>()
36+
val functionToTypeMap: Map<String, List<StubFileStructures.FunctionInfo>> by lazy {
37+
val result = mutableMapOf<String, List<StubFileStructures.FunctionInfo>>()
3838
builtinFunctions.forEach { function ->
39-
result[function.name] = function.typeInfos.map {
40-
it.function
41-
}
39+
result[function.name] = function.definitions
4240
}
4341
result
4442
}
4543

4644
val fieldToTypeMap: Map<String, List<StubFileStructures.FieldInfo>> by lazy {
4745
val result = mutableMapOf<String, List<StubFileStructures.FieldInfo>>()
4846
builtinFields.forEach { field ->
49-
result[field.name] = field.typeInfos
47+
result[field.name] = field.definitions
5048
}
5149
result
5250
}
5351

54-
val nameToClassMap: Map<String, List<StubFileStructures.ClassInfo>> by lazy {
55-
val result = mutableMapOf<String, List<StubFileStructures.ClassInfo>>()
52+
val nameToClassMap: Map<String, StubFileStructures.ClassInfo> by lazy {
53+
val result = mutableMapOf<String, StubFileStructures.ClassInfo>()
5654
builtinClasses.forEach { pyClass ->
57-
result[pyClass.name] = pyClass.typeInfos
55+
result[pyClass.className] = pyClass
5856
}
5957
result
6058
}
6159

6260
fun findTypeWithMethod(
6361
methodName: String
64-
): Set<StubFileStructures.PythonInfoType> {
65-
return (methodToTypeMap[methodName] ?: emptyList()).map {
66-
StubFileStructures.PythonInfoType(it.className, it.module)
62+
): Set<String> {
63+
return (methodToTypeMap[methodName] ?: emptyList()).mapNotNull {
64+
it.className
6765
}.toSet()
6866
}
6967

7068
fun findTypeWithField(
7169
fieldName: String
72-
): Set<StubFileStructures.PythonInfoType> {
70+
): Set<String> {
7371
return (fieldToTypeMap[fieldName] ?: emptyList()).map {
74-
StubFileStructures.PythonInfoType(it.className, it.module)
72+
it.className
7573
}.toSet()
7674
}
7775

7876
fun findTypeByFunctionWithArgumentPosition(
7977
functionName: String,
8078
argumentName: String? = null,
8179
argumentPosition: Int? = null,
82-
): Set<StubFileStructures.PythonInfoType> {
83-
val annotations = functionToAnnotationMap[functionName] ?: emptyList()
84-
val types = mutableSetOf<StubFileStructures.PythonInfoType>()
80+
): Set<String> {
81+
val annotations = functionToTypeMap[functionName] ?: emptyList()
82+
val types = mutableSetOf<String>()
8583
if (argumentName != null) {
8684
annotations.forEach { annotation ->
8785
(annotation.args + annotation.kwonlyargs).forEach {
88-
it
89-
if (it.arg == argumentName)
90-
types += it.annotation.map {
91-
ann -> StubFileStructures.PythonInfoType(ann, "")
92-
}
86+
if (it.arg == argumentName && it.annotation != null)
87+
types.add(it.annotation)
9388
}
9489
}
9590
} else if (argumentPosition != null) {
9691
annotations.forEach { annotation ->
9792
val checkCountArgs = annotation.args.size > argumentPosition
98-
if (checkCountArgs) {
99-
types += annotation.args[argumentPosition].annotation.map {
100-
ann -> StubFileStructures.PythonInfoType(ann, "")
101-
}
93+
val ann = annotation.args[argumentPosition].annotation
94+
if (checkCountArgs && ann != null) {
95+
types.add(ann)
10296
}
10397
}
10498
} else {
10599
annotations.forEach { annotation ->
106100
annotation.args.forEach {
107-
types.addAll(it.annotation.map {
108-
ann -> StubFileStructures.PythonInfoType(ann)
109-
})
101+
if (it.annotation != null)
102+
types.add(it.annotation)
110103
}
111104
}
112105
}
113106
return types
114107
}
115108

116-
fun findTypeByFunctionReturnValue(functionName: String): Set<StubFileStructures.PythonInfoType> {
117-
return functionToAnnotationMap[functionName]?.map {
118-
it.returns.map {returnType -> StubFileStructures.PythonInfoType(returnType) }
119-
}?.flatten()?.toSet() ?: emptySet()
109+
fun findTypeByFunctionReturnValue(functionName: String): Set<String> {
110+
return functionToTypeMap[functionName]?.map {
111+
it.returns
112+
}?.toSet() ?: emptySet()
120113
}
121114
}
122115

0 commit comments

Comments
 (0)