Skip to content

Update python unit test generation #1763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 192 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
1edc7d4
All current work on mypy annotations
tochilinak Nov 8, 2022
b10214b
Added some tests for AnnotationsFromMypy.kt
tochilinak Nov 8, 2022
1f4d498
Python type hierarchy in TypeMetaData
tochilinak Nov 11, 2022
771ed80
removed NamedType; removed some extra things in AnnotationsFromMypy.kt
tochilinak Nov 11, 2022
a6acacb
Finished PythonTypeWrapperForComparison
tochilinak Nov 11, 2022
594d910
Added variance in TypeVars
tochilinak Nov 11, 2022
bf0594a
Implemented mro calculation
tochilinak Nov 15, 2022
48abd93
Added PythonSubtypeChecker
tochilinak Nov 18, 2022
864285b
Fixed simple case of infinite recursion
tochilinak Nov 19, 2022
485e74c
Extracting info only about defined values in user files
tochilinak Nov 22, 2022
040232b
Added substitution by index
tochilinak Nov 25, 2022
09f61c8
Added BuiltinTypes object
tochilinak Nov 25, 2022
21827f2
added initialization of list, dict and set
tochilinak Nov 26, 2022
c721291
Extracting some other builtin types
tochilinak Nov 26, 2022
59cfedf
added extraction of argument names
tochilinak Nov 29, 2022
8155f62
Removed StatefulType
tochilinak Dec 1, 2022
5ea9e3c
Added simple constraint propagation; added createTypeWithNewAnnotatio…
tochilinak Dec 1, 2022
4cb0d1d
added PythonTypeStorage
tochilinak Dec 2, 2022
c8b101e
Changed TODO's in PythonType.kt
tochilinak Dec 2, 2022
d33d5b2
Fix in reading PythonTypeStorage
tochilinak Dec 6, 2022
26ddd03
Extract isAbstract for concrete types from mypy
tochilinak Dec 9, 2022
1d86c57
Removed some redundant files
tochilinak Dec 9, 2022
cda6acc
Added numberOfArguments in CallableTypeDescription
tochilinak Dec 9, 2022
f7028db
Added pythonTypeRepresentation
tochilinak Dec 9, 2022
98b7c61
New mypy run
tochilinak Dec 9, 2022
f53a290
Changed PythonMethod; generation of mypy check code
tochilinak Dec 13, 2022
51485c1
Added new mypy type checking
tochilinak Dec 13, 2022
c40d085
Added extraction of expression types
tochilinak Dec 16, 2022
643b1fc
New version of mypy runner
tochilinak Dec 26, 2022
c14d6c3
Added 'file to module' map
tochilinak Dec 26, 2022
ec9610e
One more case in subtype checker
tochilinak Dec 26, 2022
4991a7b
Added file to module map
tochilinak Dec 26, 2022
1398ada
Changed PythonMethod; generation of mypy check code
tochilinak Dec 13, 2022
0540546
Added Python 3.10 parser
tochilinak Oct 18, 2022
650db83
started working on type inference api
tochilinak Nov 22, 2022
e8327e6
Added ForStatement processing in HintCollector
tochilinak Nov 24, 2022
eca77f2
Added processing of bool expressions in HintCollector
tochilinak Nov 25, 2022
4c54399
Added logic for identification nodes in HintCollector
tochilinak Nov 25, 2022
86d37e3
Work on HintCollector: constant types, AdditiveExpression, List and n…
tochilinak Nov 26, 2022
24407d5
Build initialState in BaselineAlgorithm
tochilinak Nov 29, 2022
fc5422e
First version of BaselineAlgorithm
tochilinak Dec 2, 2022
dd0c8c9
Added processing of some new nodes in HintCollector
tochilinak Dec 6, 2022
2181c17
New logic of BaselineAlgorithm
tochilinak Dec 6, 2022
bb177c8
Fixed some things in generating type rating
tochilinak Dec 9, 2022
2791fc5
Added CLI for type inference
tochilinak Dec 13, 2022
987744c
Fixed bug with dependency check in type inference CLI
tochilinak Dec 16, 2022
0564a14
Regenerated python parser; fixed bug with offsets
tochilinak Dec 26, 2022
92379a0
Refactored BaselineAlgorithm; some changed in logic
tochilinak Dec 26, 2022
90465f7
TypeInferenceProcessor; fixed some bugs
tochilinak Dec 30, 2022
57af5b3
Faster version of StateExpansion
tochilinak Jan 8, 2023
d3128be
Fix; added document for testing
tochilinak Jan 9, 2023
46e0a99
A lot of small fixes
tochilinak Jan 10, 2023
958a4fc
Support of slices; fixes
tochilinak Jan 10, 2023
7563557
Added constantCollector
tochilinak Jan 11, 2023
9f73397
Added extraction of kinds of names in module from mypy
tochilinak Jan 11, 2023
edad3da
Restructure in newtyping package
tochilinak Jan 11, 2023
f1bf989
Fixed bug that failed assertion
tochilinak Jan 12, 2023
c108b9d
Changed format of names extraction
tochilinak Jan 12, 2023
88b20d1
Added resolveTypeName function
tochilinak Jan 12, 2023
11f5d4e
One more case in resolveTypeName function
tochilinak Jan 12, 2023
385e756
Added hints from isinstance calls; added penalty in createTypeRating
tochilinak Jan 12, 2023
1be8dac
Changes in mypy configuration
tochilinak Jan 12, 2023
281d90e
Fixed parsing of slices
tochilinak Jan 12, 2023
27033aa
Add BigInteger to BitVectorValue
tamarinvs19 Dec 7, 2022
9262aaa
Add string representation to Name in Type.kt
tamarinvs19 Dec 7, 2022
901d1d9
Add rendering for PythonTree
tamarinvs19 Dec 7, 2022
dd50f62
Update PythonTree model
tamarinvs19 Dec 7, 2022
0db8371
Modify python engine logic for new fuzzer
tamarinvs19 Dec 7, 2022
b5dd01b
Add PythonApi for new fuzzing
tamarinvs19 Dec 7, 2022
1764a66
Add samples for new fuzzer
tamarinvs19 Dec 7, 2022
7022afa
Add python fuzzing for dicts
tamarinvs19 Dec 7, 2022
9a26cad
Add python fuzzing for sets
tamarinvs19 Dec 7, 2022
b15b155
Refactor python fuzzing structure: split to providers
tamarinvs19 Dec 7, 2022
fdc8e67
Add Any example
tamarinvs19 Dec 7, 2022
103a7b6
Add reduce value provider
tamarinvs19 Dec 8, 2022
11708b5
Try to fix reduce code generation
tamarinvs19 Dec 8, 2022
9fdadfc
Add reduce object rendering
tamarinvs19 Dec 13, 2022
6c85233
Fix PythonApi.kt
tamarinvs19 Dec 13, 2022
ffeee13
Fix ReduceValueProvider.kt
tamarinvs19 Dec 13, 2022
d862877
Update ReduceNode rendering and fix format
tamarinvs19 Dec 7, 2022
93d9c20
Add protocol supporting
tamarinvs19 Dec 14, 2022
f4df986
Update fuzzing
tamarinvs19 Dec 15, 2022
ba7c4c7
Update codegen
tamarinvs19 Dec 19, 2022
69541b7
Try to add complex and refactoring
tamarinvs19 Dec 20, 2022
3783816
Update codegen
tamarinvs19 Dec 21, 2022
8151788
Add isCancelled to fuzzing
tamarinvs19 Dec 21, 2022
ca98d40
Fix python coverage database bug with access to database directory (#…
tamarinvs19 Dec 21, 2022
d062259
Fix string invalid format
tamarinvs19 Dec 21, 2022
2bf4ca3
Remove coroutine cancellation
tamarinvs19 Dec 21, 2022
4cc4949
Update complex value provider
tamarinvs19 Dec 26, 2022
1a059db
Add Bytes and Bytearrays, update Reduce and Int providers
tamarinvs19 Dec 29, 2022
14ad9e4
Add ConstantValueProvider
tamarinvs19 Dec 30, 2022
e273707
Refactor fuzzing, add summary
tamarinvs19 Dec 30, 2022
32ff73c
Update covered lines handler
tamarinvs19 Jan 9, 2023
fb69b8e
Update constant value provider
tamarinvs19 Jan 9, 2023
6539ac7
Update python test name generation
tamarinvs19 Jan 9, 2023
5fd2e1b
Update type representation in value providers and add pythonTypeName …
tamarinvs19 Jan 10, 2023
4ad9565
Update type representation in value providers
tamarinvs19 Jan 11, 2023
9558201
Update ReduceValueProvider, fix Overload problem
tamarinvs19 Jan 11, 2023
b4db820
Skip tests with invalid evaluation
tamarinvs19 Jan 11, 2023
404473a
Support class methods
tamarinvs19 Jan 11, 2023
3624565
Fixed codegeneration problem with python reduce objects
tamarinvs19 Jan 11, 2023
7fb219c
Add self classId to PythonTreeModel
tamarinvs19 Jan 11, 2023
06a9eca
Update logger
tamarinvs19 Jan 11, 2023
65e1335
Change log message about exception
tamarinvs19 Jan 11, 2023
755bee8
Fix commit 28f291c (Support class methods)
tamarinvs19 Jan 30, 2023
1a92e63
Add type inference
tamarinvs19 Jan 11, 2023
2729410
Change pythonObject repr
tamarinvs19 Jan 11, 2023
ff5a707
Add filter for reduce value provider
tamarinvs19 Jan 11, 2023
e1e233a
Add base annotation as the first annotations
tamarinvs19 Jan 11, 2023
f5466fc
Comment providers for Any type
tamarinvs19 Jan 11, 2023
561d4ec
Update fuzzing structure, add constants to fuzzing
tamarinvs19 Jan 11, 2023
8d7fd25
Add constants
tamarinvs19 Jan 12, 2023
c071164
Add int, float, str and bool to filter in reduce value provider
tamarinvs19 Jan 12, 2023
f6fa819
Remove double pythonBuildObject function
tamarinvs19 Jan 12, 2023
0edf4ce
Fix gradle.properties
tamarinvs19 Jan 12, 2023
b1a973e
Remove println
tamarinvs19 Jan 12, 2023
0060a2c
Update complex repr
tamarinvs19 Jan 12, 2023
646bfc5
Add int constants for float provider
tamarinvs19 Jan 12, 2023
13c65da
Update PythonTestCaseGenerator structure
tamarinvs19 Jan 12, 2023
361f9e0
Remove python3parser
tamarinvs19 Jan 12, 2023
0ff5346
Fixed mypy code generation
tochilinak Jan 13, 2023
0ea070f
Add feedback to type inference algorithm
tamarinvs19 Jan 13, 2023
7efb8eb
Fixed bug with tuple in slice; one more case in SubtypeChecker
tochilinak Jan 13, 2023
5a69eb5
Change runBlocking
tamarinvs19 Jan 13, 2023
16ad5c1
Fix method toBigInteger
tamarinvs19 Jan 13, 2023
d10b67e
Refactor stubfiles and PreprocessedValue
tamarinvs19 Jan 13, 2023
b799b0b
Update additionalModules to fuzzing
tamarinvs19 Jan 13, 2023
7cc643d
Fixed TypeInferenceProcessor
tochilinak Jan 13, 2023
345c20f
Split PythonMethod into PythonMethodDescription and PythonMethod
tochilinak Jan 15, 2023
72a017e
removed penalty in initial type rating; fixed bug in Type.pythonModul…
tochilinak Jan 17, 2023
c788543
Fixed bug in HintCollector
tochilinak Jan 18, 2023
8f9453e
Suppressed considering type feedback in type inference
tochilinak Jan 18, 2023
360d6e3
Fix bug with recursive objects
tamarinvs19 Jan 18, 2023
cc17287
Some more cases in type inference
tochilinak Jan 18, 2023
94b59e8
Update fuzzing of string
tamarinvs19 Jan 18, 2023
8dec916
Update python cg render
tamarinvs19 Jan 18, 2023
5e77eb1
Remove constants from FloatValueProvider
tamarinvs19 Jan 18, 2023
2ebee0a
Comment InvalidTypeFeedback
tamarinvs19 Jan 18, 2023
cb1c357
Remove null value from pythonTypeStorage
tamarinvs19 Jan 18, 2023
33a1dd9
Add StringUtils
tamarinvs19 Jan 18, 2023
066b06b
Added extraction of tuples as constants; some fixes
tochilinak Jan 19, 2023
e9b8c42
Fixed bug
tochilinak Jan 19, 2023
28e1d35
Added classes in type inference CLI
tochilinak Jan 19, 2023
ba390e4
Update try and import rendering
tamarinvs19 Jan 19, 2023
749c869
Add alias for python imports
tamarinvs19 Jan 19, 2023
8146d35
Remove unused import
tamarinvs19 Jan 19, 2023
2fe96fc
Update python imports
tamarinvs19 Jan 19, 2023
40260a9
Add try for arguments initialization
tamarinvs19 Jan 19, 2023
7c53eb6
Add declareOrGet
tamarinvs19 Jan 19, 2023
a3c0e5d
Update requirements
tamarinvs19 Jan 19, 2023
d4c6cb9
Add exit() when arguments are invalid
tamarinvs19 Jan 19, 2023
addf8c7
Clear memoryObjects before test method generation
tamarinvs19 Jan 19, 2023
469fc4a
Fixed extraction of nested classes
tochilinak Jan 19, 2023
1a23032
Add new memory dump parser
tamarinvs19 Jan 19, 2023
3752f86
Add nee python object deserializer
tamarinvs19 Jan 20, 2023
b03d0c8
Remove klaxon
tamarinvs19 Jan 20, 2023
e9fe1f8
New structure of Python types
tochilinak Jan 23, 2023
cf9da60
New version of utbot_mypy_runner
tochilinak Jan 23, 2023
cc0a920
Sped up annotation extraction
tochilinak Jan 23, 2023
93d8db2
Fix import bug after merge
tamarinvs19 Jan 30, 2023
3490c33
Fix problem with None return value
tamarinvs19 Jan 30, 2023
89584bf
Fix bugs with float representation, sys.exit() and self asserts
tamarinvs19 Jan 30, 2023
7f74e9a
Move documentation lines inside function body
tamarinvs19 Jan 30, 2023
43fa286
Change PythonMethodHeader construction
tamarinvs19 Jan 30, 2023
efa57de
Fix readAction error
tamarinvs19 Jan 30, 2023
be88376
Change getPythonAttributes to getPythonAttributeByName and fix accept…
tamarinvs19 Jan 31, 2023
6a2446d
Update comparison strategy for PythonTree
tamarinvs19 Jan 31, 2023
d74ecf8
Remove addition of object provider
tamarinvs19 Jan 31, 2023
c6615b2
Update test generation and fuzzing connection
tamarinvs19 Jan 31, 2023
f2be923
Add simple asserts generation for thisObject and function arguments
tamarinvs19 Jan 31, 2023
79230c1
Update requirements.txt
tamarinvs19 Jan 31, 2023
af3a5eb
Remove open
tamarinvs19 Jan 31, 2023
7e9e0cd
Fix unnecessary modifications
tamarinvs19 Jan 31, 2023
c4317b9
Fix `comparable` in deserialization algorithm
tamarinvs19 Jan 31, 2023
47d3ace
Remove empty line when it is unnecessary
tamarinvs19 Feb 1, 2023
b2f15ff
Refactor PythonEngine and PythonEvaluation
tamarinvs19 Feb 1, 2023
83c0955
Merge branch 'main' into tamarinvs19/utbot-python-stable
tamarinvs19 Feb 1, 2023
d14aca8
Remove TemporaryFileManager.setup()
tamarinvs19 Feb 1, 2023
2d804a4
Remove getPythonCodeFromPyFile
tamarinvs19 Feb 1, 2023
66ca2ca
Refactor python code execution
tamarinvs19 Feb 2, 2023
e589750
Merge branch 'main' into tamarinvs19/utbot-python-stable
tamarinvs19 Feb 6, 2023
85cb04f
Merge remote-tracking branch 'origin/tamarinvs19/utbot-python-stable'…
tamarinvs19 Feb 6, 2023
7424b06
Possible fix: save file before test generation
tamarinvs19 Feb 6, 2023
e9d29c0
Fix windows path problem: transform to UNC for mypy code
tamarinvs19 Feb 7, 2023
37fb3bc
Merge branch 'main' into tamarinvs19/utbot-python-stable
tamarinvs19 Feb 7, 2023
e80c9ee
Fix BitVectorValue to BigInteger conversion
Markoutte Feb 8, 2023
6acc19a
Add Trie to PythonFeedback
tamarinvs19 Feb 8, 2023
c22b508
Update examples
tamarinvs19 Feb 8, 2023
0949041
Fixed type inference for sample type_inference.py
tochilinak Feb 10, 2023
af32c55
Some optimizations in mypy runner
tochilinak Feb 10, 2023
6a50e85
Remove unnecessary code from build.gradle
tamarinvs19 Feb 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ target/
.gradle/
*.log
*.rdgen
utbot-intellij/src/main/resources/settings.properties
utbot-intellij/src/main/resources/settings.properties
__pycache__
.dmypy.json
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ if (pythonIde.split(",").contains(ideType)) {
include("utbot-python")
include("utbot-cli-python")
include("utbot-intellij-python")
include("utbot-python-parser")
}

if (jsIde.split(",").contains(ideType)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class UtBotPythonCli : CliktCommand(name = "UnitTestBot Python Command Line Inte
fun main(args: Array<String>) = try {
UtBotPythonCli().subcommands(
PythonGenerateTestsCommand(),
PythonRunTestsCommand()
PythonRunTestsCommand(),
PythonTypeInferenceCommand()
).main(args)
} catch (ex: Throwable) {
ex.printStackTrace()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parameters.types.long
import mu.KotlinLogging
import org.parsers.python.PythonParser
import org.utbot.framework.codegen.domain.TestFramework
import org.utbot.python.PythonMethod
import org.utbot.python.PythonMethodHeader
import org.utbot.python.PythonTestGenerationProcessor
import org.utbot.python.PythonTestGenerationProcessor.processTestGeneration
import org.utbot.python.code.PythonClass
import org.utbot.python.code.PythonCode
import org.utbot.python.framework.api.python.PythonClassId
import org.utbot.python.framework.codegen.model.Pytest
import org.utbot.python.framework.codegen.model.Unittest
import org.utbot.python.newtyping.ast.parseClassDefinition
import org.utbot.python.newtyping.ast.parseFunctionDefinition
import org.utbot.python.utils.*
import org.utbot.python.utils.RequirementsUtils.installRequirements
import org.utbot.python.utils.RequirementsUtils.requirements
import org.utbot.python.utils.getModuleName
import java.io.File
import java.nio.file.Paths

Expand Down Expand Up @@ -80,11 +83,6 @@ class PythonGenerateTestsCommand : CliktCommand(
help = "Turn off Python requirements check (to speed up)."
).flag(default = false)

private val visitOnlySpecifiedSource by option(
"--visit-only-specified-source",
help = "Do not search for classes and imported modules in other Python files from sys.path."
).flag(default = false)

private val timeout by option(
"-t", "--timeout",
help = "Specify the maximum time in milliseconds to spend on generating tests ($DEFAULT_TIMEOUT_IN_MILLIS by default)."
Expand All @@ -107,36 +105,33 @@ class PythonGenerateTestsCommand : CliktCommand(
else -> error("Not reachable")
}

private fun findCurrentPythonModule(): Optional<String> {
directoriesForSysPath.forEach { path ->
val module = getModuleName(path.toAbsolutePath(), sourceFile.toAbsolutePath())
if (module != null)
return Success(module)
}
return Fail("Couldn't find path for $sourceFile in --sys-path option. Please, specify it.")
}

private val forbiddenMethods = listOf("__init__", "__new__")

private fun getClassMethods(pythonClassFromSources: PythonClass): List<PythonMethod> =
pythonClassFromSources.methods.filter { method -> method.name !in forbiddenMethods }
private fun getPythonMethods(): Optional<List<PythonMethodHeader>> {
val parsedModule = PythonParser(sourceFileContent).Module()

private fun getPythonMethods(sourceCodeContent: String, currentModule: String): Optional<List<PythonMethod>> {
val code = PythonCode.getFromString(
sourceCodeContent,
sourceFile.toAbsolutePath(),
pythonModule = currentModule
)
?: return Fail("Couldn't parse source file. Maybe it contains syntax error?")
val topLevelFunctions = PythonCode.getTopLevelFunctions(parsedModule)
val topLevelClasses = PythonCode.getTopLevelClasses(parsedModule)

val topLevelFunctions = code.getToplevelFunctions()
val topLevelClasses = code.getToplevelClasses()
val selectedMethods = methods
if (pythonClass == null && methods == null) {
return if (topLevelFunctions.isNotEmpty())
Success(topLevelFunctions)
Success(
topLevelFunctions
.mapNotNull { parseFunctionDefinition(it) }
.map { PythonMethodHeader(it.name.toString(), sourceFile, null) }
)
else {
val topLevelClassMethods = topLevelClasses.flatMap { getClassMethods(it) }
val topLevelClassMethods = topLevelClasses
.mapNotNull { parseClassDefinition(it) }
.flatMap { cls ->
PythonCode.getClassMethods(cls.body)
.mapNotNull { parseFunctionDefinition(it) }
.map { function ->
val parsedClassName = PythonClassId(cls.name.toString())
PythonMethodHeader(function.name.toString(), sourceFile, parsedClassName)
}
}
if (topLevelClassMethods.isNotEmpty()) {
Success(topLevelClassMethods)
} else
Expand All @@ -145,19 +140,29 @@ class PythonGenerateTestsCommand : CliktCommand(
} else if (pythonClass == null && selectedMethods != null) {
val pythonMethodsOpt = selectedMethods.map { functionName ->
topLevelFunctions
.mapNotNull { parseFunctionDefinition(it) }
.map { PythonMethodHeader(it.name.toString(), sourceFile, null) }
.find { it.name == functionName }
?.let { Success(it) }
?: Fail("Couldn't find top-level function $functionName in the source file.")
}
return pack(*pythonMethodsOpt.toTypedArray())
}

val pythonClassFromSources = code.getToplevelClasses().find { it.name == pythonClass }
val pythonClassFromSources = topLevelClasses
.mapNotNull { parseClassDefinition(it) }
.find { it.name.toString() == pythonClass }
?.let { Success(it) }
?: Fail("Couldn't find class $pythonClass in the source file.")

val methods = bind(pythonClassFromSources) {
val fineMethods: List<PythonMethod> = it.methods.filter { method -> method.name !in forbiddenMethods }
val methods = bind(pythonClassFromSources) { parsedClass ->
val parsedClassId = PythonClassId(parsedClass.name.toString())
val methods = PythonCode.getClassMethods(parsedClass.body).mapNotNull { parseFunctionDefinition(it) }
val fineMethods = methods
.filter { !forbiddenMethods.contains(it.name.toString()) }
.map {
PythonMethodHeader(it.name.toString(), sourceFile, parsedClassId)
}
if (fineMethods.isNotEmpty())
Success(fineMethods)
else
Expand All @@ -178,18 +183,18 @@ class PythonGenerateTestsCommand : CliktCommand(
}

private lateinit var currentPythonModule: String
private lateinit var pythonMethods: List<PythonMethod>
private lateinit var pythonMethods: List<PythonMethodHeader>
private lateinit var sourceFileContent: String

@Suppress("UNCHECKED_CAST")
private fun calculateValues(): Optional<Unit> {
val currentPythonModuleOpt = findCurrentPythonModule()
val currentPythonModuleOpt = findCurrentPythonModule(directoriesForSysPath, sourceFile)
sourceFileContent = File(sourceFile).readText()
val pythonMethodsOpt = bind(currentPythonModuleOpt) { getPythonMethods(sourceFileContent, it) }
val pythonMethodsOpt = bind(currentPythonModuleOpt) { getPythonMethods() }

return bind(pack(currentPythonModuleOpt, pythonMethodsOpt)) {
currentPythonModule = it[0] as String
pythonMethods = it[1] as List<PythonMethod>
pythonMethods = it[1] as List<PythonMethodHeader>
Success(Unit)
}
}
Expand Down Expand Up @@ -235,12 +240,12 @@ class PythonGenerateTestsCommand : CliktCommand(
timeout = timeout,
testFramework = testFramework,
timeoutForRun = timeoutForRun,
withMinimization = !doNotMinimize,
doNotCheckRequirements = doNotCheckRequirements,
visitOnlySpecifiedSource = visitOnlySpecifiedSource,
writeTestTextToFile = { generatedCode ->
writeToFileAndSave(output, generatedCode)
},
pythonRunRoot = Paths.get("").toAbsolutePath(),
doNotCheckRequirements = doNotCheckRequirements,
withMinimization = !doNotMinimize,
checkingRequirementsAction = {
logger.info("Checking requirements...")
},
Expand All @@ -263,17 +268,12 @@ class PythonGenerateTestsCommand : CliktCommand(
)
},
processMypyWarnings = { messages -> messages.forEach { println(it) } },
finishedAction = {
logger.info("Finished test generation for the following functions: ${it.joinToString()}")
},
processCoverageInfo = { coverageReport ->
val output = coverageOutput ?: return@processTestGeneration
writeToFileAndSave(output, coverageReport)
},
pythonRunRoot = Paths.get("").toAbsolutePath()
)
}
) {
logger.info("Finished test generation for the following functions: ${it.joinToString()}")
}
}

private fun String.toAbsolutePath(): String =
File(this).canonicalPath
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.utbot.cli.language.python

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.options.split
import com.github.ajalt.clikt.parameters.types.long
import mu.KotlinLogging
import org.utbot.python.newtyping.inference.TypeInferenceProcessor
import org.utbot.python.newtyping.pythonTypeRepresentation
import org.utbot.python.utils.Fail
import org.utbot.python.utils.RequirementsUtils.requirements
import org.utbot.python.utils.Success

private val logger = KotlinLogging.logger {}

class PythonTypeInferenceCommand : CliktCommand(
name = "infer_types",
help = "Infer types for the specified Python top-level function."
) {
private val sourceFile by argument(
help = "File with Python code."
)

private val function by argument(
help = "Function to infer types for."
)

private val className by option(
"-c", "--class",
help = "Class of the function"
)

private val pythonPath by option(
"-p", "--python-path",
help = "(required) Path to Python interpreter. Use only UNC format on Windows."
).required()

private val timeout by option(
"-t", "--timout",
help = "(required) Timeout in milliseconds for type inference."
).long().required()

private val directoriesForSysPath by option(
"-s", "--sys-path",
help = "(required) Directories to add to sys.path. Use only UNC format on Windows. " +
"One of directories must contain the file with the methods under test."
).split(",").required()

private var startTime: Long = 0

override fun run() {
val moduleOpt = findCurrentPythonModule(
directoriesForSysPath.map { it.toAbsolutePath() },
sourceFile.toAbsolutePath()
)
if (moduleOpt is Fail) {
logger.error(moduleOpt.message)
}
val module = (moduleOpt as Success).value

val result = TypeInferenceProcessor(
pythonPath,
directoriesForSysPath.map{ it.toAbsolutePath() }.toSet(),
sourceFile,
module,
function,
className
).inferTypes(
startingTypeInferenceAction = {
startTime = System.currentTimeMillis()
logger.info("Starting type inference...")
},
processSignature = { logger.info("Found signature: " + it.pythonTypeRepresentation()) },
cancel = { System.currentTimeMillis() - startTime > timeout },
checkRequirementsAction = { logger.info("Checking Python requirements...") },
missingRequirementsAction = {
logger.error("Some of the following Python requirements are missing: " +
"${requirements.joinToString()}. Please install them.")
},
loadingInfoAboutTypesAction = { logger.info("Loading information about types...") },
analyzingCodeAction = { logger.info("Analyzing code...") },
pythonMethodExtractionFailAction = { logger.error(it) }
)

result.forEach { println(it.pythonTypeRepresentation()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.utbot.cli.language.python

import org.utbot.python.utils.Fail
import org.utbot.python.utils.Optional
import org.utbot.python.utils.Success
import org.utbot.python.utils.getModuleName
import java.io.File

fun findCurrentPythonModule(
directoriesForSysPath: Collection<String>,
sourceFile: String
): Optional<String> {
directoriesForSysPath.forEach { path ->
val module = getModuleName(path.toAbsolutePath(), sourceFile.toAbsolutePath())
if (module != null)
return Success(module)
}
return Fail("Couldn't find path for $sourceFile in --sys-path option. Please, specify it.")
}

fun String.toAbsolutePath(): String =
File(this).canonicalPath
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,7 @@ class BitVectorValue : KnownValue {

@Suppress("MemberVisibilityCanBePrivate")
fun toString(radix: Int, isUnsigned: Boolean = false): String {
val size = if (isUnsigned) size + 1 else size
val array = ByteArray(size / 8 + if (size % 8 != 0) 1 else 0) { index ->
toLong(bits = 8, shift = index * 8).toByte()
}
array.reverse()
return BigInteger(array).toString(radix)
return toBigInteger(isUnsigned).toString(radix)
}

override fun toString() = toString(10)
Expand All @@ -126,6 +121,17 @@ class BitVectorValue : KnownValue {
return result
}

private fun toBigInteger(isUnsigned: Boolean): BigInteger {
val size = if (isUnsigned) size + 1 else size
val array = ByteArray(size / 8 + if (size % 8 != 0) 1 else 0) { index ->
toLong(bits = 8, shift = index * 8).toByte()
}
array.reverse()
return BigInteger(array)
}

fun toBigInteger() = toBigInteger(false)

fun toBoolean() = vector[0]

fun toByte() = toLong(8).toByte()
Expand Down Expand Up @@ -155,6 +161,7 @@ class BitVectorValue : KnownValue {
is Short -> fromShort(value)
is Int -> fromInt(value)
is Long -> fromLong(value)
is BigInteger -> fromBigInteger(value)
else -> error("unknown type of value $value (${value::class})")
}
}
Expand Down Expand Up @@ -190,6 +197,17 @@ class BitVectorValue : KnownValue {
}
return BitVectorValue(size, vector)
}

fun fromBigInteger(value: BigInteger): BitVectorValue {
val size = 128
val bits = value.bitCount()
assert(bits <= size) { "This value $value is too big. Max value is 2^$bits." }
val vector = BitSet(size)
for (i in 0 until size) {
vector[i] = value.testBit(i)
}
return BitVectorValue(size, vector)
}
}
}

Expand Down
Loading