Skip to content

Commit ef1f2fd

Browse files
tochilinakVyacheslav Tamarin
andauthored
Python plugin fixes (#1848)
* plugin fixes * Added inner class filter for test function module --------- Co-authored-by: Vyacheslav Tamarin <tamairn.vs@ya.ru>
1 parent c03b4d6 commit ef1f2fd

File tree

10 files changed

+61
-34
lines changed

10 files changed

+61
-34
lines changed

utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogProcessor.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ object PythonDialogProcessor {
115115
moduleToImport,
116116
UtSettings.utBotGenerationTimeoutInMillis,
117117
DEFAULT_TIMEOUT_FOR_RUN_IN_MILLIS,
118-
visitOnlySpecifiedSource = false,
119118
cgLanguageAssistant = PythonCgLanguageAssistant,
120119
pythonPath = pythonPath,
121120
)

utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogWindow.kt

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ import com.intellij.openapi.ui.ComboBox
55
import com.intellij.openapi.ui.DialogPanel
66
import com.intellij.openapi.ui.DialogWrapper
77
import com.intellij.openapi.ui.ValidationInfo
8-
import com.intellij.ui.ColoredListCellRenderer
98
import com.intellij.ui.ContextHelpLabel
109
import com.intellij.ui.JBIntSpinner
11-
import com.intellij.ui.SimpleTextAttributes
1210
import com.intellij.ui.components.Panel
1311
import com.intellij.ui.layout.CellBuilder
1412
import com.intellij.ui.layout.Row
@@ -19,7 +17,6 @@ import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage
1917
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo
2018
import com.jetbrains.python.refactoring.classes.ui.PyMemberSelectionTable
2119
import org.utbot.framework.UtSettings
22-
import org.utbot.framework.codegen.domain.TestFramework
2320
import java.awt.BorderLayout
2421
import java.util.concurrent.TimeUnit
2522
import org.utbot.intellij.plugin.ui.components.TestSourceDirectoryChooser
@@ -51,8 +48,6 @@ class PythonDialogWindow(val model: PythonTestsModel) : DialogWrapper(model.proj
5148
private val testFrameworks =
5249
ComboBox(DefaultComboBoxModel(model.cgLanguageAssistant.getLanguageTestFrameworkManager().testFrameworks.toTypedArray()))
5350

54-
private val visitOnlySpecifiedSource = JCheckBox("Visit only specified source")
55-
5651
private lateinit var panel: DialogPanel
5752

5853
init {
@@ -96,12 +91,6 @@ class PythonDialogWindow(val model: PythonTestsModel) : DialogWrapper(model.proj
9691
row {
9792
scrollPane(functionsTable)
9893
}
99-
row {
100-
cell {
101-
component(visitOnlySpecifiedSource)
102-
component(ContextHelpLabel.create("Find argument types only in this file."))
103-
}
104-
}
10594
}
10695

10796
updateFunctionsTable()
@@ -140,7 +129,7 @@ class PythonDialogWindow(val model: PythonTestsModel) : DialogWrapper(model.proj
140129
return globalPyFunctionsToPyMemberInfo(project, functions)
141130
}
142131
return PyMemberInfoStorage(containingClass).getClassMemberInfos(containingClass)
143-
.filter { it.member is PyFunction }
132+
.filter { it.member is PyFunction && fineFunction(it.member as PyFunction) }
144133
}
145134

146135
private fun updateFunctionsTable() {
@@ -182,7 +171,6 @@ class PythonDialogWindow(val model: PythonTestsModel) : DialogWrapper(model.proj
182171
model.testFramework = testFrameworks.item
183172
model.timeout = TimeUnit.SECONDS.toMillis(timeoutSpinnerForTotalTimeout.number.toLong())
184173
model.timeoutForRun = TimeUnit.SECONDS.toMillis(timeoutSpinnerForOneRun.number.toLong())
185-
model.visitOnlySpecifiedSource = visitOnlySpecifiedSource.isSelected
186174
model.testSourceRootPath = testSourceFolderField.text
187175

188176
super.doOKAction()

utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonLanguageAssistant.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,27 @@ object PythonLanguageAssistant : LanguageAssistant() {
5959
e.getData(CommonDataKeys.PSI_ELEMENT) ?: return null
6060
}
6161

62-
val containingFunction = getContainingElement<PyFunction>(element)
63-
val containingClass = getContainingElement<PyClass>(element)
62+
val containingClass = getContainingElement<PyClass>(element) { fineClass(it) }
63+
val containingFunction: PyFunction? =
64+
if (containingClass == null)
65+
getContainingElement(element) { it.parent is PsiFile && fineFunction(it) }
66+
else
67+
getContainingElement(element) { func ->
68+
val ancestors = getAncestors(func)
69+
ancestors.dropLast(1).all { it !is PyFunction } &&
70+
ancestors.count { it is PyClass } == 1 && fineFunction(func)
71+
}
6472

6573
if (containingClass == null) {
66-
val functions = file.topLevelFunctions
74+
val functions = file.topLevelFunctions.filter { fineFunction(it) }
6775
if (functions.isEmpty())
6876
return null
6977

7078
val focusedFunction = if (functions.contains(containingFunction)) containingFunction else null
7179
return Targets(functions.toSet(), null, focusedFunction, file, editor)
7280
}
7381

74-
val functions = containingClass.methods
82+
val functions = containingClass.methods.filter { fineFunction(it) }
7583
if (functions.isEmpty())
7684
return null
7785

utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonTestsModel.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class PythonTestsModel(
2121
val currentPythonModule: String,
2222
var timeout: Long,
2323
var timeoutForRun: Long,
24-
var visitOnlySpecifiedSource: Boolean,
2524
val cgLanguageAssistant: CgLanguageAssistant,
2625
val pythonPath: String,
2726
) : BaseTestsModel(

utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/Utils.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import com.intellij.openapi.roots.ProjectFileIndex
55
import com.intellij.openapi.vfs.VfsUtil
66
import com.intellij.openapi.vfs.VirtualFile
77
import com.intellij.psi.PsiElement
8+
import com.jetbrains.python.psi.PyClass
9+
import com.jetbrains.python.psi.PyDecorator
10+
import com.jetbrains.python.psi.PyFunction
811
import org.utbot.python.utils.RequirementsUtils
912
import kotlin.random.Random
1013

@@ -19,6 +22,12 @@ inline fun <reified T : PsiElement> getContainingElement(
1922
return result as? T
2023
}
2124

25+
fun getAncestors(element: PsiElement): List<PsiElement> =
26+
if (element.parent == null)
27+
listOf(element)
28+
else
29+
getAncestors(element.parent) + element
30+
2231
fun getContentRoot(project: Project, file: VirtualFile): VirtualFile {
2332
return ProjectFileIndex.getInstance(project)
2433
.getContentRootForFile(file) ?: error("Source file lies outside of a module")
@@ -38,3 +47,12 @@ fun VirtualFile.isProjectSubmodule(ancestor: VirtualFile?): Boolean {
3847
fun checkModuleIsInstalled(pythonPath: String, moduleName: String): Boolean {
3948
return RequirementsUtils.requirementsAreInstalled(pythonPath, listOf(moduleName))
4049
}
50+
51+
fun fineFunction(function: PyFunction): Boolean =
52+
!listOf("__init__", "__new__").contains(function.name) &&
53+
function.decoratorList?.decorators?.isNotEmpty() != true // TODO: add processing of simple decorators
54+
//(function.parent !is PyDecorator || (function.parent as PyDecorator).isBuiltin)
55+
56+
fun fineClass(pyClass: PyClass): Boolean =
57+
getAncestors(pyClass).dropLast(1).all { it !is PyClass && it !is PyFunction } &&
58+
pyClass.methods.any { fineFunction(it) }

utbot-python/samples/easy_samples/general.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class Dummy:
1313
def propagate(self):
1414
return [self, self]
1515

16+
@staticmethod
17+
def abs(x):
18+
return abs(x)
19+
1620

1721
def dict_f(x, a, b, c):
1822
y = {1: 2}

utbot-python/samples/easy_samples/sample_classes.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from dataclasses import dataclass
22

3+
34
class A:
45
def __init__(self, val: int):
56
self.description = val
@@ -19,3 +20,17 @@ class C:
1920

2021
def inc(self):
2122
self.counter += 1
23+
24+
25+
class Outer:
26+
class Inner:
27+
a = 1
28+
29+
def inc(self):
30+
self.a += 1
31+
32+
def __init__(self):
33+
self.inner = Outer.Inner()
34+
35+
def inc1(self):
36+
self.inner.inc()

utbot-python/samples/easy_samples/subtypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ def func_for_P(x: P) -> None:
2626

2727

2828
class R(Protocol):
29-
def f(self) -> R:
29+
def f(self) -> 'R':
3030
...
3131

3232

3333
class RImpl:
34-
def f(self) -> RImpl:
34+
def f(self) -> 'RImpl':
3535
return self
3636

3737

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ class PythonEngine(
158158
val argumentModules = argumentValues
159159
.flatMap { it.allContainingClassIds }
160160
.map { it.moduleName }
161-
val localAdditionalModules = (additionalModules + argumentModules).toSet()
161+
.filterNot { it.startsWith(moduleToImport) }
162+
val localAdditionalModules = (additionalModules + argumentModules + moduleToImport).toSet()
162163

163164
return PythonCodeExecutorImpl(
164165
methodUnderTest,
Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
package org.utbot.python.newtyping.ast
22

33
import org.parsers.python.PythonParser
4+
import org.utbot.python.PythonMethodHeader
5+
import org.utbot.python.code.PythonCode
46

57
fun main() {
68
val content = """
7-
def calc_to_goal_cost(trajectory, goal):
8-
""${'"'}
9-
calc to goal cost with angle difference
10-
""${'"'}
11-
12-
dx = goal[0] - trajectory[-1, 0]
13-
dy = goal[1] - trajectory[-1, 1]
14-
error_angle = math.atan2(dy, dx)
15-
cost_angle = error_angle - trajectory[-1, 2]
16-
cost = abs(math.atan2(math.sin(cost_angle), math.cos(cost_angle)))
17-
18-
return cost
9+
class A:
10+
@decorator
11+
def func(x):
12+
return 1
1913
""".trimIndent()
2014

2115
val root = PythonParser(content).Module()
16+
// val y = PythonCode.findFunctionDefinition(root, PythonMethodHeader("func", "", null))
2217
val x = root
2318
}

0 commit comments

Comments
 (0)