Skip to content

Commit af01b6e

Browse files
authored
UTBot Python updates (#2481)
1 parent f08a328 commit af01b6e

File tree

17 files changed

+311
-108
lines changed

17 files changed

+311
-108
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import typing
2+
3+
4+
def make_recursive_list(x: int):
5+
xs = [1, 2]
6+
xs.append(xs)
7+
xs.append(x)
8+
return xs
9+
10+
11+
def make_recursive_dict(x: int, y: int):
12+
d = {1: 2}
13+
d[x] = d
14+
d[y] = x
15+
return d
16+
17+
18+
if __name__ == '__main__':
19+
make_recursive_dict(3, 4)

utbot-python/samples/samples/primitives/regex.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ def check_regex(string: str) -> bool:
66
if re.match(pattern, string):
77
return True
88
return False
9+
10+
11+
def create_pattern(string: str):
12+
if len(string) > 10:
13+
return re.compile(rf"{string}")
14+
else:
15+
return re.compile(string)

utbot-python/samples/samples/primitives/str_example.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,12 @@ def starts_with(s: str):
4848

4949

5050
def join_str(strings: typing.List[str]):
51-
return "--".join(strings)
51+
return "--".join(strings)
52+
53+
54+
def separated_str(x: int):
55+
if x == 1:
56+
return r"fjalsdk\\nfjlask"
57+
if 1 < x < 100:
58+
return "fjalsd\n" * x
59+
return x

utbot-python/samples/test_configuration.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,17 @@
167167
}
168168
]
169169
},
170+
{
171+
"name": "recursive",
172+
"groups": [
173+
{
174+
"classes": null,
175+
"methods": null,
176+
"timeout": 30,
177+
"coverage": 100
178+
}
179+
]
180+
},
170181
{
171182
"name": "sets",
172183
"groups": [
@@ -433,7 +444,7 @@
433444
{
434445
"classes": null,
435446
"methods": null,
436-
"timeout": 40,
447+
"timeout": 50,
437448
"coverage": 100
438449
}
439450
]
@@ -445,7 +456,7 @@
445456
"classes": null,
446457
"methods": null,
447458
"timeout": 160,
448-
"coverage": 100
459+
"coverage": 110
449460
}
450461
]
451462
}

utbot-python/src/main/kotlin/org/utbot/python/evaluation/serialiation/PythonObjectParser.kt

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ object PythonObjectParser {
3232
class MemoryDump(
3333
private val objects: MutableMap<String, MemoryObject>
3434
) {
35+
fun contains(id: String): Boolean {
36+
return objects.containsKey(id)
37+
}
38+
3539
fun getById(id: String): MemoryObject {
3640
return objects[id]!!
3741
}
@@ -41,7 +45,7 @@ class MemoryDump(
4145
}
4246
}
4347

44-
class TypeInfo(
48+
data class TypeInfo(
4549
val module: String,
4650
val kind: String,
4751
) {
@@ -88,82 +92,82 @@ class ReduceMemoryObject(
8892
val dictitems: String
8993
) : MemoryObject(id, typeinfo, comparable)
9094

91-
fun PythonTree.PythonTreeNode.toMemoryObject(memoryDump: MemoryDump): String {
95+
fun PythonTree.PythonTreeNode.toMemoryObject(memoryDump: MemoryDump, reload: Boolean = false): String {
96+
val id = this.id.toString()
97+
if (memoryDump.contains(id) && !reload) return id
98+
99+
val typeinfo = TypeInfo(this.type.moduleName, this.type.typeName)
92100
val obj = when (this) {
93101
is PythonTree.PrimitiveNode -> {
94102
ReprMemoryObject(
95-
this.id.toString(),
96-
TypeInfo(this.type.moduleName, this.type.typeName),
103+
id,
104+
typeinfo,
97105
this.comparable,
98-
this.repr
106+
this.repr.replace("\n", "\\\n").replace("\r", "\\\r")
99107
)
100108
}
101109

102110
is PythonTree.ListNode -> {
111+
val draft = ListMemoryObject(id, typeinfo, this.comparable, emptyList())
112+
memoryDump.addObject(draft)
113+
103114
val items = this.items.entries
104-
.sortedBy { it.key }
105115
.map { it.value.toMemoryObject(memoryDump) }
106-
ListMemoryObject(
107-
this.id.toString(),
108-
TypeInfo(this.type.moduleName, this.type.typeName),
109-
this.comparable,
110-
items
111-
)
116+
ListMemoryObject(id, typeinfo, this.comparable, items)
112117
}
113118

114119
is PythonTree.TupleNode -> {
115120
val items = this.items.entries
116-
.sortedBy { it.key }
117121
.map { it.value.toMemoryObject(memoryDump) }
118-
ListMemoryObject(
119-
this.id.toString(),
120-
TypeInfo(this.type.moduleName, this.type.typeName),
121-
this.comparable,
122-
items
123-
)
122+
ListMemoryObject(id, typeinfo, this.comparable, items)
124123
}
125124

126125
is PythonTree.SetNode -> {
127126
val items = this.items.map { it.toMemoryObject(memoryDump) }
128-
ListMemoryObject(
129-
this.id.toString(),
130-
TypeInfo(this.type.moduleName, this.type.typeName),
131-
this.comparable,
132-
items
133-
)
127+
ListMemoryObject(id, typeinfo, this.comparable, items)
134128
}
135129

136130
is PythonTree.DictNode -> {
131+
val draft = DictMemoryObject(id, typeinfo, this.comparable, emptyMap())
132+
memoryDump.addObject(draft)
133+
137134
val items = this.items.entries
138135
.associate {
139136
it.key.toMemoryObject(memoryDump) to it.value.toMemoryObject(memoryDump)
140137
}
141-
DictMemoryObject(
142-
this.id.toString(),
143-
TypeInfo(this.type.moduleName, this.type.typeName),
144-
this.comparable,
145-
items
146-
)
138+
DictMemoryObject(id, typeinfo, this.comparable, items)
147139
}
148140

149141
is PythonTree.ReduceNode -> {
142+
val argsIds = PythonTree.ListNode(this.args.withIndex().associate { it.index to it.value }.toMutableMap())
143+
val draft = ReduceMemoryObject(
144+
id,
145+
typeinfo,
146+
this.comparable,
147+
TypeInfo(
148+
this.constructor.moduleName,
149+
this.constructor.typeName,
150+
),
151+
argsIds.toMemoryObject(memoryDump),
152+
"",
153+
"",
154+
"",
155+
)
156+
memoryDump.addObject(draft)
157+
150158
val stateObjId = if (this.customState) {
151159
this.state["state"]!!
152160
} else {
153161
PythonTree.DictNode(this.state.entries.associate {
154162
PythonTree.fromString(it.key) to it.value
155163
}.toMutableMap())
156164
}
157-
val argsIds = PythonTree.ListNode(this.args.withIndex().associate { it.index to it.value }.toMutableMap())
158165
val listItemsIds =
159166
PythonTree.ListNode(this.listitems.withIndex().associate { it.index to it.value }.toMutableMap())
160167
val dictItemsIds = PythonTree.DictNode(this.dictitems.toMutableMap())
161168
ReduceMemoryObject(
162-
this.id.toString(),
163-
TypeInfo(
164-
this.type.moduleName,
165-
this.type.typeName,
166-
),
169+
id,
170+
typeinfo,
167171
this.comparable,
168172
TypeInfo(
169173
this.constructor.moduleName,
@@ -200,33 +204,36 @@ fun MemoryObject.toPythonTree(
200204
}
201205

202206
is DictMemoryObject -> {
203-
PythonTree.DictNode(
207+
val draft = PythonTree.DictNode(
204208
id,
205-
items.entries.associate {
206-
memoryDump.getById(it.key).toPythonTree(memoryDump, visited) to
207-
memoryDump.getById(it.value).toPythonTree(memoryDump, visited)
208-
}.toMutableMap()
209+
mutableMapOf()
209210
)
211+
visited[this.id] = draft
212+
items.entries.map {
213+
draft.items[memoryDump.getById(it.key).toPythonTree(memoryDump, visited)] =
214+
memoryDump.getById(it.value).toPythonTree(memoryDump, visited)
215+
}
216+
draft
210217
}
211218

212219
is ListMemoryObject -> {
213-
val elementsMap = items.withIndex().associate {
214-
it.index to
215-
memoryDump.getById(it.value).toPythonTree(memoryDump, visited)
216-
}.toMutableMap()
217-
when (this.qualname) {
218-
"builtins.tuple" -> {
219-
PythonTree.TupleNode(this.id.toLong(), elementsMap)
220-
}
221-
222-
"builtins.set" -> {
223-
PythonTree.SetNode(this.id.toLong(), elementsMap.values.toMutableSet())
224-
}
220+
val draft = when (this.qualname) {
221+
"builtins.tuple" -> PythonTree.TupleNode(id, mutableMapOf())
222+
"builtins.set" -> PythonTree.SetNode(id, mutableSetOf())
223+
else -> PythonTree.ListNode(id, mutableMapOf())
224+
}
225+
visited[this.id] = draft
225226

226-
else -> {
227-
PythonTree.ListNode(this.id.toLong(), elementsMap)
227+
items.mapIndexed { index, valueId ->
228+
val value = memoryDump.getById(valueId).toPythonTree(memoryDump, visited)
229+
when (draft) {
230+
is PythonTree.TupleNode -> draft.items[index] = value
231+
is PythonTree.SetNode -> draft.items.add(value)
232+
is PythonTree.ListNode -> draft.items[index] = value
233+
else -> {}
228234
}
229235
}
236+
draft
230237
}
231238

232239
is ReduceMemoryObject -> {

utbot-python/src/main/kotlin/org/utbot/python/framework/api/python/PythonTree.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ object PythonTree {
5353

5454
open val children: List<PythonTreeNode> = emptyList()
5555

56+
fun isRecursive(): Boolean {
57+
return isRecursiveObject(this)
58+
}
59+
5660
override fun toString(): String {
5761
return type.name + children.toString()
5862
}

utbot-python/src/main/kotlin/org/utbot/python/framework/api/python/util/PythonIdUtils.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ val pythonSetClassId = PythonClassId("builtins.set")
2020
val pythonBytearrayClassId = PythonClassId("builtins.bytearray")
2121
val pythonBytesClassId = PythonClassId("builtins.bytes")
2222
val pythonExceptionClassId = PythonClassId("builtins.Exception")
23+
val pythonRePatternClassId = PythonClassId("re.Pattern")

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
293293
emptyLineIfNeeded()
294294
if (elementsHaveSameStructure) {
295295
val index = newVar(pythonNoneClassId, keyName) {
296-
CgLiteral(pythonNoneClassId, "None")
296+
CgPythonRepr(pythonNoneClassId, "None")
297297
}
298298
forEachLoop {
299299
innerBlock {
@@ -346,6 +346,12 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
346346
depth: Int = maxDepth,
347347
useExpectedAsValue: Boolean = false
348348
) {
349+
if (!expectedNode.comparable && expectedNode.isRecursive()) {
350+
emptyLineIfNeeded()
351+
comment("Cannot compare recursive objects") // TODO: add special function for recursive comparison
352+
assertIsInstance(expected, actual)
353+
return
354+
}
349355
if (expectedNode.comparable || depth == 0) {
350356
val expectedValue = if (useExpectedAsValue) {
351357
expected

0 commit comments

Comments
 (0)