Skip to content

Commit

Permalink
Merge pull request #298 from koxudaxi/fix_wrong_call_parameters_when_…
Browse files Browse the repository at this point in the history
…init_is_defined

Fix wrong call parameters when init is defined
  • Loading branch information
koxudaxi authored May 13, 2021
2 parents b7b734c + f6a5e70 commit 77e8aab
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 4 deletions.
3 changes: 2 additions & 1 deletion resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
<h2>version 0.3.2</h2>
<p>BugFixes</p>
<ul>
<li>Fix wrong an error for a duplicate in config. [#297]</li>
<li>Fix wrong call parameters when init is defined [#298]</li>
<li>Fix wrong an error for a duplicate in config [#297]</li>
</ul>
<h2>version 0.3.1</h2>
<p>Features</p>
Expand Down
13 changes: 11 additions & 2 deletions src/com/koxudaxi/pydantic/Pydantic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ fun getPyClassByPyKeywordArgument(pyKeywordArgument: PyKeywordArgument, context:
fun isPydanticModel(pyClass: PyClass, includeDataclass: Boolean, context: TypeEvalContext): Boolean {
return (isSubClassOfPydanticBaseModel(pyClass,
context) || isSubClassOfPydanticGenericModel(pyClass,
context) || (includeDataclass && pyClass.isPydanticDataclass)) && !pyClass.isPydanticBaseModel && !pyClass.isPydanticGenericModel
context) || (includeDataclass && pyClass.isPydanticDataclass)) && !pyClass.isPydanticBaseModel
&& !pyClass.isPydanticGenericModel && !pyClass.isBaseSettings
}

val PyClass.isPydanticBaseModel: Boolean get() = qualifiedName == BASE_MODEL_Q_NAME
Expand All @@ -163,7 +164,7 @@ internal fun isSubClassOfBaseSetting(pyClass: PyClass, context: TypeEvalContext)
return pyClass.isSubclass(BASE_SETTINGS_Q_NAME, context)
}

internal val PyClass.isBaseSetting: Boolean get() = qualifiedName == BASE_SETTINGS_Q_NAME
internal val PyClass.isBaseSettings: Boolean get() = qualifiedName == BASE_SETTINGS_Q_NAME


internal fun hasDecorator(pyDecoratable: PyDecoratable, refNames: List<QualifiedName>): Boolean {
Expand Down Expand Up @@ -583,4 +584,12 @@ internal fun getQualifiedName(pyExpression: PyExpression, context: TypeEvalConte
.firstOrNull()
else -> return null
}
}

fun getPydanticModelInit(pyClass: PyClass, context: TypeEvalContext): PyFunction? {
val pyFunction = pyClass.findInitOrNew(true, context) ?: return null
if (pyFunction.name != "__init__") return null
val containingClass = pyFunction.containingClass ?: return null
if (!isPydanticModel(containingClass, false, context)) return null
return pyFunction
}
1 change: 1 addition & 0 deletions src/com/koxudaxi/pydantic/PydanticCompletionContributor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class PydanticCompletionContributor : CompletionContributor() {
?: return

if (!isPydanticModel(pyClass, true, typeEvalContext)) return
if (getPydanticModelInit(pyClass, typeEvalContext) is PyFunction) return

val definedSet = pyArgumentList.children
.mapNotNull { (it as? PyKeywordArgument)?.name }
Expand Down
10 changes: 9 additions & 1 deletion src/com/koxudaxi/pydantic/PydanticTypeProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ class PydanticTypeProvider : PyTypeProviderBase() {

private fun getBaseSetting(pyClass: PyClass, context: TypeEvalContext): PyClass? {
return pyClass.getSuperClasses(context).mapNotNull {
if (it.isBaseSetting) {
if (it.isBaseSettings) {
it
} else {
getBaseSetting(it, context)
Expand Down Expand Up @@ -464,6 +464,14 @@ class PydanticTypeProvider : PyTypeProviderBase() {
): PyCallableType? {
if (!isPydanticModel(pyClass, false, context)) return null
val clsType = (context.getType(pyClass) as? PyClassLikeType) ?: return null

getPydanticModelInit(pyClass, context)?.let {
val callParameters = it.parameterList.parameters
.filterNot { parameter -> parameter.isSelf }
.map { parameter -> PyCallableParameterImpl.psi(parameter) }
return PyCallableTypeImpl(callParameters, clsType.toInstance())
}

val ellipsis = PyElementGenerator.getInstance(pyClass.project).createEllipsis()

val typed = !init || getInstance(pyClass.project).currentInitTyped
Expand Down
9 changes: 9 additions & 0 deletions testData/completionv18/overrideInitField.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pydantic import BaseModel


class A(BaseModel):
abc: str = '123'
def __init__(self, xyz: int):
pass

A().<caret>
9 changes: 9 additions & 0 deletions testData/completionv18/overrideInitKeywordArgument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pydantic import BaseModel


class A(BaseModel):
abc: str = '123'
def __init__(self, xyz: int):
pass

A(<caret>)
55 changes: 55 additions & 0 deletions testData/typeinspectionv18/overrideInit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from pydantic import BaseModel


class A(BaseModel):
abc: str = '123'
def __init__(self):
pass
A()

class B(BaseModel):
abc: str = '123'
def __init__(self, a: float, b: int):
pass
B(abc='123'<warning descr="null">)</warning>

class C(BaseModel):
abc: str = '123'
def __init__(self, a: float, b: int = 123):
pass

C(abc='123'<warning descr="null">)</warning>


# class D(BaseModel):
# abc: str = '123'
# def __init__(self, *a):
# pass
#
# C(abc='123')
#
# class E(BaseModel):
# abc: str = '123'
# def __init__(self, **a):
# pass
# E(abc='123')

class F(C):
abc: str = '123'

def __init__(self, c: float, d: str):
super(F, self).__init__(...)
F(abc='123'<warning descr="null">)</warning>

class G(C):
abc: str = '123'

def __new__(self, c: float, d: str):
super(F, self).__init__(...)
G(abc='123')


class H(C):
pass

H(abc='123'<warning descr="null">)</warning>
10 changes: 10 additions & 0 deletions testSrc/com/koxudaxi/pydantic/PydanticCompletionV18Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,15 @@ open class PydanticCompletionV18Test : PydanticTestCase(version = "v18") {
Pair("ET", "null"))
)
}
fun testOverrideInitKeywordArgument() {
doFieldTest(
listOf()
)
}
fun testOverrideInitField() {
doFieldTest(
listOf(Pair("abc", "str='123' A"))
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ open class PydanticTypeInspectionV18Test : PydanticInspectionBase("v18") {
fun testGenericModel() {
doTest()
}

fun testOverrideInit() {
doTest()
}
}

0 comments on commit 77e8aab

Please sign in to comment.