diff --git a/utbot-python/samples/easy_samples/generics.py b/utbot-python/samples/easy_samples/generics.py new file mode 100644 index 0000000000..e0939f3e4e --- /dev/null +++ b/utbot-python/samples/easy_samples/generics.py @@ -0,0 +1,24 @@ +from typing import TypeVar, Generic +from logging import Logger + +T = TypeVar('T', bound=bool) +U = TypeVar('U', str, object) + + +class LoggedVar(Generic[T]): + def __init__(self, value: T, name: str) -> None: + self.name = name + self.value = value + + def set(self, new: T) -> None: + self.value = new + + def get(self, x: U): + return self.value, x + + +def func(x: T, y: U): + if x: + return y + else: + return 100 diff --git a/utbot-python/src/main/kotlin/org/utbot/python/PythonTestCaseGenerator.kt b/utbot-python/src/main/kotlin/org/utbot/python/PythonTestCaseGenerator.kt index 6187355209..d7bb80153b 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/PythonTestCaseGenerator.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/PythonTestCaseGenerator.kt @@ -13,8 +13,7 @@ import org.utbot.python.newtyping.* import org.utbot.python.newtyping.ast.visitor.Visitor import org.utbot.python.newtyping.ast.visitor.constants.ConstantCollector import org.utbot.python.newtyping.ast.visitor.hints.HintCollector -import org.utbot.python.newtyping.general.FunctionType -import org.utbot.python.newtyping.general.Type +import org.utbot.python.newtyping.general.* import org.utbot.python.newtyping.inference.InferredTypeFeedback import org.utbot.python.newtyping.inference.InvalidTypeFeedback import org.utbot.python.newtyping.inference.SuccessFeedback @@ -25,6 +24,7 @@ import org.utbot.python.newtyping.mypy.MypyReportLine import org.utbot.python.newtyping.mypy.getErrorNumber import org.utbot.python.newtyping.utils.getOffsetLine import org.utbot.python.typing.MypyAnnotations +import org.utbot.python.utils.PriorityCartesianProduct import java.io.File private val logger = KotlinLogging.logger {} @@ -44,16 +44,19 @@ class PythonTestCaseGenerator( private val mypyStorage: MypyAnnotationStorage, private val mypyReportLine: List, private val mypyConfigFile: File, -){ +) { private val storageForMypyMessages: MutableList = mutableListOf() private fun findMethodByDescription(mypyStorage: MypyAnnotationStorage, method: PythonMethodHeader): PythonMethod { - val containingClass = method.containingPythonClassId - val functionDef = if (containingClass == null) { + var containingClass: CompositeType? = null + val containingClassName = method.containingPythonClassId?.simpleName + val functionDef = if (containingClassName == null) { mypyStorage.definitions[curModule]!![method.name]!!.getUtBotDefinition()!! } else { - mypyStorage.definitions[curModule]!![containingClass.simpleName]!!.type.asUtBotType.getPythonAttributes().first { + containingClass = + mypyStorage.definitions[curModule]!![containingClassName]!!.getUtBotType() as CompositeType + mypyStorage.definitions[curModule]!![containingClassName]!!.type.asUtBotType.getPythonAttributes().first { it.meta.name == method.name } } as? PythonFunctionDefinition ?: error("Selected method is not a function definition") @@ -64,7 +67,7 @@ class PythonTestCaseGenerator( return PythonMethod( name = method.name, moduleFilename = method.moduleFilename, - containingPythonClassId = method.containingPythonClassId, + containingPythonClass = containingClass, codeAsString = funcDef.body.source, definition = functionDef, ast = funcDef.body @@ -84,13 +87,64 @@ class PythonTestCaseGenerator( } ?: emptyMap() val namesStorage = GlobalNamesStorage(mypyStorage) - val hintCollector = HintCollector(method.definition, typeStorage, mypyExpressionTypes , namesStorage, curModule) + val hintCollector = HintCollector(method.definition, typeStorage, mypyExpressionTypes, namesStorage, curModule) val constantCollector = ConstantCollector(typeStorage) val visitor = Visitor(listOf(hintCollector, constantCollector)) visitor.visit(method.ast) return Pair(hintCollector, constantCollector) } + private fun getCandidates(param: TypeParameter, typeStorage: PythonTypeStorage): List { + val meta = param.pythonDescription() as PythonTypeVarDescription + return when (meta.parameterKind) { + PythonTypeVarDescription.ParameterKind.WithConcreteValues -> { + param.constraints.map { it.boundary } + } + PythonTypeVarDescription.ParameterKind.WithUpperBound -> { + typeStorage.simpleTypes.filter { + if (it.hasBoundedParameters()) + return@filter false + val bound = param.constraints.first().boundary + PythonSubtypeChecker.checkIfRightIsSubtypeOfLeft(bound, it, typeStorage) + } + } + } + } + + private val maxSubstitutions = 10 + + private fun generateTypesAfterSubstitution(type: Type, typeStorage: PythonTypeStorage): List { + val params = type.getBoundedParameters() + return PriorityCartesianProduct(params.map { getCandidates(it, typeStorage) }).getSequence().map { subst -> + DefaultSubstitutionProvider.substitute(type, (params zip subst).associate { it }) + }.take(maxSubstitutions).toList() + } + + private fun substituteTypeParameters(method: PythonMethod, typeStorage: PythonTypeStorage): List { + val newClasses = + if (method.containingPythonClass != null) { + generateTypesAfterSubstitution(method.containingPythonClass, typeStorage) + } else { + listOf(null) + } + return newClasses.flatMap { newClass -> + val funcType = newClass?.getPythonAttributeByName(typeStorage, method.name)?.type as? FunctionType + ?: method.definition.type + val newFuncTypes = generateTypesAfterSubstitution(funcType, typeStorage) + newFuncTypes.map { newFuncType -> + val def = PythonFunctionDefinition(method.definition.meta, newFuncType as FunctionType) + PythonMethod( + method.name, + method.moduleFilename, + newClass as? CompositeType, + method.codeAsString, + def, + method.ast + ) + } + }.take(maxSubstitutions) + } + fun generate(methodDescription: PythonMethodHeader): PythonTestSet { storageForMypyMessages.clear() @@ -108,65 +162,69 @@ class PythonTestCaseGenerator( var missingLines: Set? = null val coveredLines = mutableSetOf() var generated = 0 - val typeInferenceCancellation = { isCancelled() || System.currentTimeMillis() >= until || missingLines?.size == 0 } + val typeInferenceCancellation = + { isCancelled() || System.currentTimeMillis() >= until || missingLines?.size == 0 } - inferAnnotations( - method, - mypyStorage, - typeStorage, - hintCollector, - mypyReportLine, - mypyConfigFile, - typeInferenceCancellation - ) { functionType -> - val args = (functionType as FunctionType).arguments - - logger.info { "Inferred annotations: ${ args.joinToString { it.pythonTypeRepresentation() } }" } - - val engine = PythonEngine( - method, - directoriesForSysPath, - curModule, - pythonPath, - constants, - timeoutForRun, - coveredLines, - PythonTypeStorage.get(mypyStorage) - ) - - var coverageLimit = COVERAGE_LIMIT - var coveredBefore = coveredLines.size - - var feedback: InferredTypeFeedback = SuccessFeedback - - val fuzzerCancellation = { typeInferenceCancellation() || coverageLimit == 0 } // || feedback is InvalidTypeFeedback } - - engine.fuzzing(args, fuzzerCancellation, until).collect { - generated += 1 - when (it) { - is ValidExecution -> { - executions += it.utFuzzedExecution - missingLines = updateCoverage(it.utFuzzedExecution, coveredLines, missingLines) - feedback = SuccessFeedback - } - is InvalidExecution -> { - errors += it.utError - feedback = SuccessFeedback - } - is ArgumentsTypeErrorFeedback -> { - feedback = InvalidTypeFeedback + substituteTypeParameters(method, typeStorage).forEach { newMethod -> + inferAnnotations( + newMethod, + mypyStorage, + typeStorage, + hintCollector, + mypyReportLine, + mypyConfigFile, + typeInferenceCancellation + ) { functionType -> + val args = (functionType as FunctionType).arguments + + logger.info { "Inferred annotations: ${args.joinToString { it.pythonTypeRepresentation() }}" } + + val engine = PythonEngine( + newMethod, + directoriesForSysPath, + curModule, + pythonPath, + constants, + timeoutForRun, + coveredLines, + PythonTypeStorage.get(mypyStorage) + ) + + var coverageLimit = COVERAGE_LIMIT + var coveredBefore = coveredLines.size + + var feedback: InferredTypeFeedback = SuccessFeedback + + val fuzzerCancellation = + { typeInferenceCancellation() || coverageLimit == 0 } // || feedback is InvalidTypeFeedback } + + engine.fuzzing(args, fuzzerCancellation, until).collect { + generated += 1 + when (it) { + is ValidExecution -> { + executions += it.utFuzzedExecution + missingLines = updateCoverage(it.utFuzzedExecution, coveredLines, missingLines) + feedback = SuccessFeedback + } + is InvalidExecution -> { + errors += it.utError + feedback = SuccessFeedback + } + is ArgumentsTypeErrorFeedback -> { + feedback = InvalidTypeFeedback + } + is TypeErrorFeedback -> { + feedback = InvalidTypeFeedback + } } - is TypeErrorFeedback -> { - feedback = InvalidTypeFeedback + val coveredAfter = coveredLines.size + if (coveredAfter == coveredBefore) { + coverageLimit -= 1 } + coveredBefore = coveredAfter } - val coveredAfter = coveredLines.size - if (coveredAfter == coveredBefore) { - coverageLimit -= 1 - } - coveredBefore = coveredAfter + feedback } - feedback } @@ -231,13 +289,13 @@ class PythonTestCaseGenerator( mypyConfigFile ) - runBlocking breaking@ { + runBlocking breaking@{ if (isCancelled()) { return@breaking } val existsAnnotation = method.definition.type - if (existsAnnotation.arguments.all {it.pythonTypeName() != "typing.Any"}) { + if (existsAnnotation.arguments.all { it.pythonTypeName() != "typing.Any" }) { annotationHandler(existsAnnotation) } diff --git a/utbot-python/src/main/kotlin/org/utbot/python/UTPythonAPI.kt b/utbot-python/src/main/kotlin/org/utbot/python/UTPythonAPI.kt index fa5bda5f57..e0d3bbda9c 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/UTPythonAPI.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/UTPythonAPI.kt @@ -7,6 +7,7 @@ import org.utbot.python.framework.api.python.PythonClassId import org.utbot.python.framework.api.python.PythonModel import org.utbot.python.framework.api.python.util.pythonAnyClassId import org.utbot.python.newtyping.* +import org.utbot.python.newtyping.general.CompositeType import org.utbot.python.typing.MypyAnnotations data class PythonArgument(val name: String, val annotation: String?) @@ -20,7 +21,7 @@ class PythonMethodHeader( class PythonMethod( val name: String, val moduleFilename: String, - val containingPythonClassId: PythonClassId?, + val containingPythonClass: CompositeType?, val codeAsString: String, var definition: PythonFunctionDefinition, val ast: Block @@ -34,7 +35,7 @@ class PythonMethod( TODO: Now we think that all class methods has `self` argument! We should support `@property` decorator */ val hasThisArgument: Boolean - get() = containingPythonClassId != null + get() = containingPythonClass != null val arguments: List get() { diff --git a/utbot-python/src/main/kotlin/org/utbot/python/evaluation/PythonCodeExecutorImpl.kt b/utbot-python/src/main/kotlin/org/utbot/python/evaluation/PythonCodeExecutorImpl.kt index 8fff56e926..b56812fe90 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/evaluation/PythonCodeExecutorImpl.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/evaluation/PythonCodeExecutorImpl.kt @@ -7,6 +7,7 @@ import org.utbot.python.FunctionArguments import org.utbot.python.PythonMethod import org.utbot.python.code.PythonCodeGenerator import org.utbot.python.framework.api.python.util.pythonAnyClassId +import org.utbot.python.newtyping.pythonTypeRepresentation import org.utbot.python.utils.TemporaryFileManager import org.utbot.python.utils.getResult import org.utbot.python.utils.startProcess @@ -63,7 +64,7 @@ class PythonCodeExecutorImpl( return Coverage( coveredInstructions=covered.map { Instruction( - method.containingPythonClassId?.name ?: pythonAnyClassId.name, + method.containingPythonClass?.pythonTypeRepresentation() ?: pythonAnyClassId.name, method.methodSignature(), it, it.toLong() @@ -72,7 +73,7 @@ class PythonCodeExecutorImpl( instructionsCount = statements.size.toLong(), missedInstructions = missedStatements.map { Instruction( - method.containingPythonClassId?.name ?: pythonAnyClassId.name, + method.containingPythonClass?.pythonTypeRepresentation() ?: pythonAnyClassId.name, method.methodSignature(), it, it.toLong() diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt index 9b006fbfef..8bb24450a9 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt @@ -42,6 +42,7 @@ import org.utbot.python.newtyping.pythonAnyType import org.utbot.python.newtyping.pythonModules import org.utbot.python.newtyping.pythonTypeRepresentation import org.utbot.python.framework.codegen.toPythonRawString +import org.utbot.python.newtyping.pythonDescription class PythonCodeGenerator( classUnderTest: ClassId, @@ -113,7 +114,7 @@ class PythonCodeGenerator( val executorModuleName = "utbot_executor.executor" val executorModuleNameAlias = "__utbot_executor" val executorFunctionName = "$executorModuleNameAlias.run_calculate_function_value" - val failArgumentsFunctionName = "$executorModuleNameAlias.fail_arguments_initialization" + val failArgumentsFunctionName = "$executorModuleNameAlias.fail_argument_initialization" val importExecutor = PythonUserImport(executorModuleName, alias_ = executorModuleNameAlias) val importSys = PythonSystemImport("sys") @@ -133,12 +134,12 @@ class PythonCodeGenerator( val outputPath = CgLiteral(pythonStrClassId, fileForOutputName.toPythonRawString()) val databasePath = CgLiteral(pythonStrClassId, coverageDatabasePath.toPythonRawString()) - val containingClass = method.containingPythonClassId + val containingClass = method.containingPythonClass var functionTextName = if (containingClass == null) method.name else - "${containingClass.simpleName}.${method.name}" + "${containingClass.pythonDescription().name.name}.${method.name}" if (functionModule.isNotEmpty()) { functionTextName = "$functionModule.$functionTextName" } diff --git a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt index e070410ca8..3cecc34fe7 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt @@ -13,22 +13,7 @@ import org.utbot.fuzzing.Seed import org.utbot.fuzzing.Statistic import org.utbot.fuzzing.utils.Trie import org.utbot.python.framework.api.python.PythonTree -import org.utbot.python.fuzzing.provider.BoolValueProvider -import org.utbot.python.fuzzing.provider.BytearrayValueProvider -import org.utbot.python.fuzzing.provider.BytesValueProvider -import org.utbot.python.fuzzing.provider.ComplexValueProvider -import org.utbot.python.fuzzing.provider.ConstantValueProvider -import org.utbot.python.fuzzing.provider.DictValueProvider -import org.utbot.python.fuzzing.provider.FloatValueProvider -import org.utbot.python.fuzzing.provider.IntValueProvider -import org.utbot.python.fuzzing.provider.ListValueProvider -import org.utbot.python.fuzzing.provider.NoneValueProvider -import org.utbot.python.fuzzing.provider.ReduceValueProvider -import org.utbot.python.fuzzing.provider.SetValueProvider -import org.utbot.python.fuzzing.provider.StrValueProvider -import org.utbot.python.fuzzing.provider.TupleFixSizeValueProvider -import org.utbot.python.fuzzing.provider.TupleValueProvider -import org.utbot.python.fuzzing.provider.UnionValueProvider +import org.utbot.python.fuzzing.provider.* import org.utbot.python.fuzzing.provider.utils.isAny import org.utbot.python.newtyping.PythonProtocolDescription import org.utbot.python.newtyping.PythonSubtypeChecker @@ -79,6 +64,7 @@ fun pythonDefaultValueProviders(idGenerator: IdGenerator) = listOf( BytearrayValueProvider, ReduceValueProvider(idGenerator), ConstantValueProvider, + TypeAliasValueProvider ) class PythonFuzzing( diff --git a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/ReduceValueProvider.kt b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/ReduceValueProvider.kt index f91f43075c..90ed8046a0 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/ReduceValueProvider.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/ReduceValueProvider.kt @@ -36,17 +36,37 @@ class ReduceValueProvider( } override fun generate(description: PythonMethodDescription, type: Type) = sequence { - val initMethods = type.getPythonAttributeByName(description.pythonTypeStorage, "__init__") - val newMethods = type.getPythonAttributeByName(description.pythonTypeStorage, "__new__") - val constructors = listOfNotNull(initMethods, newMethods) + val initMethodName = "__init__" + val newMethodName = "__new__" + val typeDescr = type.pythonDescription() + val constructors = + if (typeDescr is PythonCompositeTypeDescription) { + val mro = typeDescr.mro(description.pythonTypeStorage, type) + val initParent = mro.indexOfFirst { p -> p.getPythonAttributes().any { it.meta.name == initMethodName } } + val newParent = mro.indexOfFirst { p -> p.getPythonAttributes().any { it.meta.name == newMethodName } } + val initMethods = type.getPythonAttributeByName(description.pythonTypeStorage, initMethodName) + val newMethods = type.getPythonAttributeByName(description.pythonTypeStorage, newMethodName) + if (initParent <= newParent && initMethods != null) { + listOf(initMethods) + } else if (newMethods != null) { + listOf(newMethods) + } else { + emptyList() // probably not reachable (because of class object) + } + } else { + emptyList() + } constructors .forEach { // TODO: here we need to use same as .getPythonAttributeByName but without name // TODO: now we do not have fields from parents val fields = type.getPythonAttributes() .filter { attr -> - !(attr.meta.name.startsWith("__") && attr.meta.name.endsWith("__") && attr.meta.name.length >= 4) - attr.type.getPythonAttributeByName(description.pythonTypeStorage, "__call__") == null + !(attr.meta.name.startsWith("__") && attr.meta.name.endsWith("__") && attr.meta.name.length >= 4) && + (attr.meta as? PythonVariableDescription)?.isProperty != true && attr.type.getPythonAttributeByName( + description.pythonTypeStorage, + "__call__" + ) == null } val modifications = emptyList>().toMutableList() @@ -65,7 +85,9 @@ class ReduceValueProvider( constructorFunction: FunctionType, modifications: Sequence> ): Seed.Recursive { - val arguments = constructorFunction.arguments + val description = constructorFunction.pythonDescription() as PythonCallableTypeDescription + val positionalArgs = description.argumentKinds.count { it == PythonCallableTypeDescription.ArgKind.ARG_POS } + val arguments = constructorFunction.arguments.take(positionalArgs) val nonSelfArgs = arguments.drop(1) return Seed.Recursive( diff --git a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/TypeAliasValueProvider.kt b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/TypeAliasValueProvider.kt new file mode 100644 index 0000000000..53f906ed34 --- /dev/null +++ b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/provider/TypeAliasValueProvider.kt @@ -0,0 +1,33 @@ +package org.utbot.python.fuzzing.provider + +import org.utbot.fuzzing.Routine +import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.ValueProvider +import org.utbot.python.framework.api.python.PythonTree +import org.utbot.python.fuzzing.PythonFuzzedValue +import org.utbot.python.fuzzing.PythonMethodDescription +import org.utbot.python.newtyping.PythonTypeAliasDescription +import org.utbot.python.newtyping.general.Type +import org.utbot.python.newtyping.pythonTypeRepresentation + +object TypeAliasValueProvider : ValueProvider { + + override fun accept(type: Type): Boolean { + return type.meta is PythonTypeAliasDescription + } + + override fun generate(description: PythonMethodDescription, type: Type): Sequence> { + val compositeType = PythonTypeAliasDescription.castToCompatibleTypeApi(type) + return sequenceOf( + Seed.Recursive( + construct = Routine.Create(listOf(compositeType.members[0])) { v -> v.first() }, + empty = Routine.Empty { + PythonFuzzedValue( + PythonTree.fromObject(), + "%var% = ${type.pythonTypeRepresentation()}" + ) + } + ) + ) + } +} \ No newline at end of file diff --git a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/PythonTypeStorage.kt b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/PythonTypeStorage.kt index 8f1e170c9d..de699bda89 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/PythonTypeStorage.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/PythonTypeStorage.kt @@ -3,6 +3,7 @@ package org.utbot.python.newtyping import org.utbot.python.newtyping.general.CompositeType import org.utbot.python.newtyping.general.DefaultSubstitutionProvider import org.utbot.python.newtyping.general.Type +import org.utbot.python.newtyping.general.getOrigin import org.utbot.python.newtyping.mypy.ClassDef import org.utbot.python.newtyping.mypy.CompositeAnnotationNode import org.utbot.python.newtyping.mypy.MypyAnnotation @@ -23,6 +24,16 @@ class PythonTypeStorage( val pythonSlice: Type, val allTypes: Set ) { + + val simpleTypes: List + get() = allTypes.filter { + val description = it.pythonDescription() + !description.name.name.startsWith("_") + && description is PythonConcreteCompositeTypeDescription + && !description.isAbstract + && !listOf("typing", "typing_extensions").any { mod -> description.name.prefix == listOf(mod) } + }.sortedBy { type -> if (type.pythonTypeName().startsWith("builtins")) 0 else 1 } + companion object { private fun getNestedClasses(cur: MypyAnnotation, result: MutableSet) { val type = cur.asUtBotType diff --git a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/TypeInferenceProcessor.kt b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/TypeInferenceProcessor.kt index 4c403d6aae..ef7d2f6f2d 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/TypeInferenceProcessor.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/TypeInferenceProcessor.kt @@ -160,7 +160,7 @@ class TypeInferenceProcessor( val result = PythonMethod( functionName, path.toString(), - PythonClassId("$moduleOfSourceFile.$className"), + typeOfClass, sourceFileContent.substring(funcDef.body.beginOffset, funcDef.body.endOffset).trimIndent(), defOfFunc, funcDef.body diff --git a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/baseline/TypeCandidateGeneration.kt b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/baseline/TypeCandidateGeneration.kt index f0b4601a6f..fb7aa6af6d 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/baseline/TypeCandidateGeneration.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/baseline/TypeCandidateGeneration.kt @@ -178,14 +178,7 @@ fun createGeneralTypeRating(hintCollectorResult: HintCollectorResult, storage: P val dictOfAny = DefaultSubstitutionProvider.substituteAll(storage.pythonDict, listOf(pythonAnyType, pythonAnyType)) val prefix = listOf(int, listOfAny, str, bool, float, dictOfAny) val rating = createTypeRating( - storage.allTypes.filter { - val description = it.pythonDescription() - !description.name.name.startsWith("_") - && description is PythonConcreteCompositeTypeDescription - && !description.isAbstract - && !listOf("typing", "typing_extensions").any { mod -> description.name.prefix == listOf(mod) } - && !prefix.any { type -> typesAreEqual(type.getOrigin(), it) } - }, + storage.simpleTypes.filter { !prefix.any { type -> typesAreEqual(type.getOrigin(), it) } }, allLowerBounds, allUpperBounds, storage, diff --git a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/test.kt b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/test.kt index f8f0669826..28b73907fe 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/test.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/newtyping/inference/test.kt @@ -6,10 +6,10 @@ fun main() { TypeInferenceProcessor( "python3.9", directoriesForSysPath = setOf("/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples"), - "/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples/easy_samples/boruvka.py", - moduleOfSourceFile = "easy_samples.boruvka", - "boruvka", - className = "Graph" + "/home/tochilinak/Documents/projects/utbot/UTBotJava/utbot-python/samples/easy_samples/generics.py", + moduleOfSourceFile = "easy_samples.generics", + "set", + className = "LoggedVar" ).inferTypes(cancel = { false }).forEach { println(it.pythonTypeRepresentation()) } diff --git a/utbot-python/src/test/kotlin/org/utbot/python/newtyping/mypy/MypyStorageKtTest.kt b/utbot-python/src/test/kotlin/org/utbot/python/newtyping/mypy/MypyStorageKtTest.kt index fe6a6d2475..c50a8d571f 100644 --- a/utbot-python/src/test/kotlin/org/utbot/python/newtyping/mypy/MypyStorageKtTest.kt +++ b/utbot-python/src/test/kotlin/org/utbot/python/newtyping/mypy/MypyStorageKtTest.kt @@ -10,11 +10,13 @@ import org.utbot.python.newtyping.general.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class MypyStorageKtTest { lateinit var storage: MypyAnnotationStorage + lateinit var typeStorage: PythonTypeStorage lateinit var storageBoruvka: MypyAnnotationStorage @BeforeAll fun setup() { val sample = MypyStorageKtTest::class.java.getResource("/annotation_sample.json")!!.readText() storage = readMypyAnnotationStorage(sample) + typeStorage = PythonTypeStorage.get(storage) val sample1 = MypyStorageKtTest::class.java.getResource("/boruvka.json")!!.readText() storageBoruvka = readMypyAnnotationStorage(sample1) } @@ -65,6 +67,17 @@ internal class MypyStorageKtTest { assertTrue((setOfInts.getPythonAttributes().find { it.meta.name == "add" }!!.type as FunctionType).arguments[1] == int) } + @Test + fun testSubstitution2() { + val counter = storage.definitions["collections"]!!["Counter"]!!.getUtBotType() as CompositeType + val int = storage.definitions["builtins"]!!["int"]!!.getUtBotType() as CompositeType + val counterOfInt = DefaultSubstitutionProvider.substituteByIndex(counter, 0, int) + val subtract = counterOfInt.getPythonAttributeByName(typeStorage, "subtract")!!.type.parameters[2] as FunctionType + val iterable = storage.definitions["typing"]!!["Iterable"]!!.getUtBotType() + val iterableOfInt = DefaultSubstitutionProvider.substituteByIndex(iterable, 0, int) + assertTrue(typesAreEqual(subtract.arguments.last(), iterableOfInt)) + } + @Test fun testUserClass() { val classA = storage.definitions["annotation_tests"]!!["A"]!!.getUtBotType() as CompositeType