Skip to content

Commit db1b250

Browse files
committed
Add reduce object rendering
1 parent eeb6843 commit db1b250

File tree

5 files changed

+234
-105
lines changed

5 files changed

+234
-105
lines changed

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.utbot.framework.codegen.domain.models.TestClassModel
1717
import org.utbot.framework.codegen.renderer.CgAbstractRenderer
1818
import org.utbot.framework.codegen.renderer.CgPrinterImpl
1919
import org.utbot.framework.codegen.renderer.CgRendererContext
20+
import org.utbot.framework.codegen.tree.CgTestClassConstructor.CgComponents.clearContextRelatedStorage
2021
import org.utbot.python.PythonMethod
2122
import org.utbot.python.code.AnnotationProcessor.getModulesFromAnnotation
2223
import org.utbot.python.framework.api.python.NormalizedPythonAnnotation
@@ -30,12 +31,13 @@ import org.utbot.framework.plugin.api.MockFramework
3031
import org.utbot.framework.plugin.api.UtModel
3132
import org.utbot.python.framework.api.python.PythonTreeModel
3233
import org.utbot.python.framework.codegen.PythonCgLanguageAssistant
33-
import org.utbot.python.framework.codegen.model.constructor.tree.PythonCgMethodConstructor
3434
import org.utbot.python.framework.codegen.model.constructor.tree.PythonCgTestClassConstructor
35+
import org.utbot.python.framework.codegen.model.constructor.tree.PythonCgVariableConstructor
3536
import org.utbot.python.framework.codegen.model.constructor.visitor.CgPythonRenderer
3637
import org.utbot.python.framework.codegen.model.tree.CgPythonDict
3738
import org.utbot.python.framework.codegen.model.tree.CgPythonFunctionCall
3839
import org.utbot.python.framework.codegen.model.tree.CgPythonList
40+
import org.utbot.python.framework.codegen.model.tree.CgPythonTree
3941

4042
class PythonCodeGenerator(
4143
classUnderTest: ClassId,
@@ -107,65 +109,77 @@ class PythonCodeGenerator(
107109
moduleToImport: String,
108110
additionalModules: Set<String> = emptySet(),
109111
fileForOutputName: String
110-
): String {
111-
val renderer = CgAbstractRenderer.makeRenderer(context) as CgPythonRenderer
112-
113-
val executorFunctionName = "run_calculate_function_value"
114-
val executorModuleName = "utbot_executor.executor"
115-
116-
val importExecutor = PythonUserImport(executorFunctionName, executorModuleName)
117-
val importSys = PythonSystemImport("sys")
118-
val importSysPaths = directoriesForSysPath.map { PythonSysPathImport(it) }
119-
val importFunction = PythonUserImport("*", moduleToImport)
120-
val imports =
121-
listOf(importSys) + importSysPaths + listOf(importExecutor, importFunction) + additionalModules.map { PythonUserImport(it) }
122-
123-
val containingClass = method.containingPythonClassId
124-
val functionName =
125-
if (containingClass == null)
126-
CgLiteral(pythonAnyClassId, method.name)
127-
else
128-
CgLiteral(pythonAnyClassId, "${containingClass.name}.${method.name}")
129-
130-
val arguments = method.arguments.map { argument ->
131-
CgVariable(argument.name, argument.annotation?.let { PythonClassId(it) } ?: pythonAnyClassId)
132-
}
133-
134-
val parameters = methodArguments.zip(arguments).map { (model, argument) ->
135-
val obj = (context.cgLanguageAssistant.getMethodConstructorBy(context) as PythonCgMethodConstructor).pythonBuildObject((model as PythonTreeModel).tree)
136-
CgAssignment(
137-
argument,
138-
obj
112+
): String = withCustomContext(testClassCustomName = null) {
113+
context.withTestClassFileScope {
114+
clearContextRelatedStorage()
115+
(context.cgLanguageAssistant as PythonCgLanguageAssistant).memoryObjects.clear()
116+
117+
val renderer = CgAbstractRenderer.makeRenderer(context) as CgPythonRenderer
118+
119+
val executorFunctionName = "run_calculate_function_value"
120+
val executorModuleName = "utbot_executor.executor"
121+
122+
val importExecutor = PythonUserImport(executorFunctionName, executorModuleName)
123+
val importSys = PythonSystemImport("sys")
124+
val importSysPaths = directoriesForSysPath.map { PythonSysPathImport(it) }
125+
val importFunction = PythonUserImport("*", moduleToImport)
126+
val imports =
127+
listOf(importSys) + importSysPaths + listOf(importExecutor, importFunction) + additionalModules.map { PythonUserImport(it) }
128+
imports.forEach {
129+
renderer.renderPythonImport(it)
130+
}
131+
132+
val containingClass = method.containingPythonClassId
133+
val functionName =
134+
if (containingClass == null)
135+
CgLiteral(pythonAnyClassId, method.name)
136+
else
137+
CgLiteral(pythonAnyClassId, "${containingClass.name}.${method.name}")
138+
139+
val arguments = method.arguments.map { argument ->
140+
CgVariable(argument.name, argument.annotation?.let { PythonClassId(it) } ?: pythonAnyClassId)
141+
}
142+
143+
val parameters = methodArguments.zip(arguments).map { (model, argument) ->
144+
if (model is PythonTreeModel) {
145+
val obj = (context.cgLanguageAssistant.getVariableConstructorBy(context) as PythonCgVariableConstructor).getOrCreateVariable(model)
146+
(obj as CgPythonTree).children.forEach { it.accept(renderer) }
147+
148+
CgAssignment(
149+
argument,
150+
obj.value
151+
)
152+
} else {
153+
CgAssignment(argument, CgLiteral(model.classId, model.toString()))
154+
}
155+
}
156+
157+
val args = CgPythonList(emptyList())
158+
val kwargs = CgPythonDict(
159+
arguments.associateBy { argument -> CgLiteral(pythonStrClassId, "'${argument.name}'") }
139160
)
140-
}
141-
142-
val args = CgPythonList(emptyList())
143-
val kwargs = CgPythonDict(
144-
arguments.associateBy { argument -> CgLiteral(pythonStrClassId, "'${argument.name}'") }
145-
)
146161

147-
val fullpath = CgLiteral(pythonStrClassId, "'${method.moduleFilename}'")
162+
val fullpath = CgLiteral(pythonStrClassId, "'${method.moduleFilename}'")
148163

149-
val outputPath = CgLiteral(pythonStrClassId, "'$fileForOutputName'")
164+
val outputPath = CgLiteral(pythonStrClassId, "'$fileForOutputName'")
150165

151-
val executorCall = CgPythonFunctionCall(
152-
pythonNoneClassId,
153-
executorFunctionName,
154-
listOf(
155-
functionName,
156-
args,
157-
kwargs,
158-
fullpath,
159-
outputPath,
166+
val executorCall = CgPythonFunctionCall(
167+
pythonNoneClassId,
168+
executorFunctionName,
169+
listOf(
170+
functionName,
171+
args,
172+
kwargs,
173+
fullpath,
174+
outputPath,
175+
)
160176
)
161-
)
162177

163-
imports.forEach {
164-
renderer.renderPythonImport(it)
178+
parameters.forEach { it.accept(renderer) }
179+
executorCall.accept(renderer)
180+
181+
renderer.toString()
165182
}
166-
parameters.forEach { it.accept(renderer) }
167-
executorCall.accept(renderer)
168-
return renderer.toString()
169183
}
170184

171185
fun generateMypyCheckCode(

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
3030
(execution.result as UtExplicitlyThrownException).exception.message?.let {
3131
emptyLineIfNeeded()
3232
comment("raises $it")
33+
println("pass")
3334
}
3435

3536
else -> {
@@ -83,8 +84,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
8384
}
8485
}
8586
}
86-
87-
fun pythonBuildObject(objectNode: PythonTree.PythonTreeNode): CgValue {
87+
private fun pythonBuildObject(objectNode: PythonTree.PythonTreeNode): CgValue {
8888
return when (objectNode) {
8989
is PythonTree.PrimitiveNode -> {
9090
CgLiteral(objectNode.type, objectNode.repr)

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

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package org.utbot.python.framework.codegen.model.constructor.tree
22

33
import org.utbot.framework.codegen.domain.context.CgContext
4+
import org.utbot.framework.codegen.domain.models.CgAssignment
45
import org.utbot.framework.codegen.domain.models.CgConstructorCall
6+
import org.utbot.framework.codegen.domain.models.CgFieldAccess
57
import org.utbot.framework.codegen.domain.models.CgLiteral
8+
import org.utbot.framework.codegen.domain.models.CgMethodCall
9+
import org.utbot.framework.codegen.domain.models.CgStatement
610
import org.utbot.framework.codegen.domain.models.CgValue
711
import org.utbot.framework.codegen.domain.models.CgVariable
812
import org.utbot.framework.codegen.tree.CgTestClassConstructor
913
import org.utbot.framework.codegen.tree.CgVariableConstructor
1014
import org.utbot.framework.plugin.api.ConstructorId
15+
import org.utbot.framework.plugin.api.FieldId
1116
import org.utbot.framework.plugin.api.UtModel
1217
import org.utbot.python.framework.api.python.*
18+
import org.utbot.python.framework.api.python.util.pythonNoneClassId
19+
import org.utbot.python.framework.codegen.PythonCgLanguageAssistant
1320
import org.utbot.python.framework.codegen.model.tree.*
1421

1522
class PythonCgVariableConstructor(context_: CgContext) : CgVariableConstructor(context_) {
@@ -21,7 +28,10 @@ class PythonCgVariableConstructor(context_: CgContext) : CgVariableConstructor(c
2128
when (model) {
2229
is PythonBoolModel -> CgLiteral(model.classId, model.value)
2330
is PythonPrimitiveModel -> CgLiteral(model.classId, model.value)
24-
is PythonTreeModel -> CgPythonTree(model.classId, model.tree)
31+
is PythonTreeModel -> {
32+
val (value, children) = pythonBuildObject2(model.tree)
33+
CgPythonTree(model.classId, model.tree, value, children)
34+
}
2535
is PythonInitObjectModel -> constructInitObjectModel(model, baseName)
2636
is PythonDictModel -> CgPythonDict(model.stores.map {
2737
getOrCreateVariable(it.key) to getOrCreateVariable(
@@ -47,4 +57,115 @@ class PythonCgVariableConstructor(context_: CgContext) : CgVariableConstructor(c
4757
)
4858
}
4959
}
60+
61+
fun pythonBuildObject2(objectNode: PythonTree.PythonTreeNode): Pair<CgValue, List<CgStatement>> {
62+
return when (objectNode) {
63+
is PythonTree.PrimitiveNode -> {
64+
Pair(CgLiteral(objectNode.type, objectNode.repr), emptyList())
65+
}
66+
67+
is PythonTree.ListNode -> {
68+
val items = objectNode.items.values.map { pythonBuildObject2(it) }
69+
Pair(CgPythonList(items.map { it.first }), items.flatMap { it.second })
70+
}
71+
72+
is PythonTree.TupleNode -> {
73+
val items = objectNode.items.values.map { pythonBuildObject2(it) }
74+
Pair(CgPythonTuple(items.map { it.first }), items.flatMap { it.second })
75+
}
76+
77+
is PythonTree.SetNode -> {
78+
val items = objectNode.items.map { pythonBuildObject2(it) }
79+
Pair(CgPythonSet(items.map { it.first }.toSet()), items.flatMap { it.second })
80+
}
81+
82+
is PythonTree.DictNode -> {
83+
val keys = objectNode.items.keys.map { pythonBuildObject2(it) }
84+
val values = objectNode.items.values.map { pythonBuildObject2(it) }
85+
Pair(CgPythonDict(
86+
keys.zip(values).map { (key, value) ->
87+
key.first to value.first
88+
}.toMap()
89+
), keys.flatMap { it.second } + values.flatMap { it.second })
90+
}
91+
92+
is PythonTree.ReduceNode -> {
93+
val id = objectNode.id
94+
val children = emptyList<CgStatement>().toMutableList()
95+
if ((context.cgLanguageAssistant as PythonCgLanguageAssistant).memoryObjects.containsKey(id)) {
96+
return Pair(
97+
(context.cgLanguageAssistant as PythonCgLanguageAssistant).memoryObjects[id]!!,
98+
children
99+
)
100+
}
101+
102+
val initArgs = objectNode.args.map {
103+
val buildObj = pythonBuildObject2(it)
104+
children += buildObj.second
105+
buildObj.first
106+
}
107+
val constructor = ConstructorId(
108+
objectNode.constructor,
109+
initArgs.map { it.type }
110+
)
111+
val constructorCall = CgConstructorCall(constructor, initArgs)
112+
val obj = newVar(objectNode.type) {
113+
constructorCall
114+
}
115+
children.add(CgAssignment(obj, constructorCall))
116+
117+
(context.cgLanguageAssistant as PythonCgLanguageAssistant).memoryObjects[id] = obj
118+
119+
val state = objectNode.state.map { (key, value) ->
120+
val buildObj = pythonBuildObject2(value)
121+
children.addAll(buildObj.second)
122+
key to buildObj.first
123+
}.toMap()
124+
val listitems = objectNode.listitems.map {
125+
val buildObj = pythonBuildObject2(it)
126+
children.addAll(buildObj.second)
127+
buildObj.first
128+
}
129+
val dictitems = objectNode.dictitems.map { (key, value) ->
130+
val keyObj = pythonBuildObject2(key)
131+
val valueObj = pythonBuildObject2(value)
132+
children.addAll(keyObj.second)
133+
children.addAll(valueObj.second)
134+
keyObj.first to valueObj.first
135+
}
136+
137+
state.forEach { (key, value) ->
138+
val fieldAccess = CgFieldAccess(obj, FieldId(objectNode.type, key))
139+
children.add(CgAssignment(fieldAccess, value))
140+
}
141+
listitems.forEach {
142+
val methodCall = CgMethodCall(
143+
obj,
144+
PythonMethodId(
145+
obj.type as PythonClassId,
146+
"append",
147+
NormalizedPythonAnnotation(pythonNoneClassId.name),
148+
listOf(RawPythonAnnotation(it.type.name))
149+
),
150+
listOf(it)
151+
)
152+
children.add(methodCall)
153+
}
154+
dictitems.forEach { (key, value) ->
155+
val index = CgPythonIndex(
156+
value.type as PythonClassId,
157+
obj,
158+
key
159+
)
160+
children.add(CgAssignment(index, value))
161+
}
162+
163+
return Pair(obj, children)
164+
}
165+
166+
else -> {
167+
throw UnsupportedOperationException()
168+
}
169+
}
170+
}
50171
}

0 commit comments

Comments
 (0)