Skip to content

Commit 4eee309

Browse files
authored
Support __setstate__ for custom state of python objects (#2300)
Support __setstate__ for custom state
1 parent 762090b commit 4eee309

File tree

6 files changed

+65
-12
lines changed

6 files changed

+65
-12
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import typing
2+
3+
4+
class MyClass:
5+
__slots__ = ['a', 'b']
6+
7+
def __init__(self, a: int, b: typing.Dict[int, str]):
8+
self.a = a
9+
self.b = b
10+
11+
def __eq__(self, other):
12+
return self.a == other.a and self.b == other.b
13+
14+
def __setstate__(self, state):
15+
self.a = state[1]['a']
16+
self.b = state[1]['b']
17+
18+
19+
def make_my_class(a: int, b: typing.Dict[int, str]) -> MyClass:
20+
return MyClass(a, b)

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,13 @@ fun PythonTree.PythonTreeNode.toMemoryObject(memoryDump: MemoryDump): String {
147147
}
148148

149149
is PythonTree.ReduceNode -> {
150-
val stateObjId = PythonTree.DictNode(this.state.entries.associate {
151-
PythonTree.fromString(it.key) to it.value
152-
}.toMutableMap())
150+
val stateObjId = if (this.customState) {
151+
this.state["state"]!!
152+
} else {
153+
PythonTree.DictNode(this.state.entries.associate {
154+
PythonTree.fromString(it.key) to it.value
155+
}.toMutableMap())
156+
}
153157
val argsIds = PythonTree.ListNode(this.args.withIndex().associate { it.index to it.value }.toMutableMap())
154158
val listItemsIds =
155159
PythonTree.ListNode(this.listitems.withIndex().associate { it.index to it.value }.toMutableMap())
@@ -226,7 +230,9 @@ fun MemoryObject.toPythonTree(
226230
}
227231

228232
is ReduceMemoryObject -> {
229-
val stateObjs = memoryDump.getById(state) as DictMemoryObject
233+
val stateObjsDraft = memoryDump.getById(state)
234+
val customState = stateObjsDraft !is DictMemoryObject
235+
230236
val arguments = memoryDump.getById(args) as ListMemoryObject
231237
val listitemsObjs = memoryDump.getById(listitems) as ListMemoryObject
232238
val dictitemsObjs = memoryDump.getById(dictitems) as DictMemoryObject
@@ -236,13 +242,20 @@ fun MemoryObject.toPythonTree(
236242
PythonClassId(this.constructor.module, this.constructor.kind),
237243
arguments.items.map { memoryDump.getById(it).toPythonTree(memoryDump, visited) },
238244
)
245+
prevObj.customState = customState
239246
visited[this.id] = prevObj
240247

241-
prevObj.state = stateObjs.items.entries.associate {
242-
(memoryDump.getById(it.key).toPythonTree(memoryDump, visited) as PythonTree.PrimitiveNode)
243-
.repr.drop(1).dropLast(1) to
244-
memoryDump.getById(it.value).toPythonTree(memoryDump, visited)
245-
}.toMutableMap()
248+
prevObj.state = if (prevObj.customState) {
249+
val stateObjs = memoryDump.getById(state)
250+
mutableMapOf("state" to stateObjs.toPythonTree(memoryDump, visited))
251+
} else {
252+
val stateObjs = memoryDump.getById(state) as DictMemoryObject
253+
stateObjs.items.entries.associate {
254+
(memoryDump.getById(it.key).toPythonTree(memoryDump, visited) as PythonTree.PrimitiveNode)
255+
.repr.drop(1).dropLast(1) to
256+
memoryDump.getById(it.value).toPythonTree(memoryDump, visited)
257+
}.toMutableMap()
258+
}
246259
prevObj.listitems = listitemsObjs.items.map { memoryDump.getById(it).toPythonTree(memoryDump, visited) }
247260
prevObj.dictitems = dictitemsObjs.items.entries.associate {
248261
memoryDump.getById(it.key).toPythonTree(memoryDump, visited) to

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ object PythonTree {
212212
var state: MutableMap<String, PythonTreeNode>,
213213
var listitems: List<PythonTreeNode>,
214214
var dictitems: Map<PythonTreeNode, PythonTreeNode>,
215+
var customState: Boolean = false, // if this field is true, state must have structure {'state': <PythonTreeNode>}
215216
) : PythonTreeNode(id, type) {
216217
constructor(
217218
type: PythonClassId,

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,23 @@ class PythonCgVariableConstructor(cgContext: CgContext) : CgVariableConstructor(
107107
keyObj to valueObj
108108
}
109109

110-
state.forEach { (key, value) ->
111-
obj[FieldId(objectNode.type, key)] `=` value
110+
if (objectNode.customState) {
111+
val setstate = state["state"]!!
112+
val methodCall = CgMethodCall(
113+
obj,
114+
PythonMethodId(
115+
obj.type as PythonClassId,
116+
"__setstate__",
117+
NormalizedPythonAnnotation(pythonNoneClassId.name),
118+
listOf(RawPythonAnnotation(setstate.type.name))
119+
),
120+
listOf(setstate)
121+
)
122+
+methodCall
123+
} else {
124+
state.forEach { (key, value) ->
125+
obj[FieldId(objectNode.type, key)] `=` value
126+
}
112127
}
113128
listitems.forEach {
114129
val methodCall = CgMethodCall(

utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/ReduceValueProvider.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ object ReduceValueProvider : ValueProvider<Type, PythonFuzzedValue, PythonMethod
5959
.forEach {
6060
// TODO: here we need to use same as .getPythonAttributeByName but without name
6161
// TODO: now we do not have fields from parents
62+
// val slots = type.getPythonAttributeByName(description.pythonTypeStorage, "__slots__")
63+
// if (slots != null) {
64+
// TODO: here we should use only attributes from __slots__
65+
//}
6266
val fields = type.getPythonAttributes()
6367
.filter { attr ->
6468
!(attr.meta.name.startsWith("__") && attr.meta.name.endsWith("__") && attr.meta.name.length >= 4) &&

utbot-python/src/main/kotlin/org/utbot/python/utils/RequirementsUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package org.utbot.python.utils
33
object RequirementsUtils {
44
val requirements: List<String> = listOf(
55
"mypy==1.0.0",
6-
"utbot-executor==1.4.26",
6+
"utbot-executor==1.4.31",
77
"utbot-mypy-runner==0.2.8",
88
)
99

0 commit comments

Comments
 (0)