Skip to content

Commit

Permalink
Merge pull request #287 from koxudaxi/fix_format
Browse files Browse the repository at this point in the history
Fix format
  • Loading branch information
koxudaxi authored May 3, 2021
2 parents a2bb9cd + 8eb041f commit 28abc47
Show file tree
Hide file tree
Showing 35 changed files with 1,061 additions and 823 deletions.
1 change: 1 addition & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<h2>version 0.3.1</h2>
<p>Features</p>
<ul>
<li>Fix format [#287]</li>
<li>Improve handling pydantic version [#286]</li>
<li>Support config parameters on class kwargs [#285]</li>
</ul>
Expand Down
14 changes: 11 additions & 3 deletions src/com/koxudaxi/pydantic/Pydantic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ import com.jetbrains.extensions.QNameResolveContext
import com.jetbrains.extensions.resolveToElement
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider
import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.impl.*
import com.jetbrains.python.psi.impl.PyStarArgumentImpl
import com.jetbrains.python.psi.impl.PyTargetExpressionImpl
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.resolve.PyResolveUtil
import com.jetbrains.python.psi.types.*
import com.jetbrains.python.sdk.*
import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.isAssociatedWithModule
import com.jetbrains.python.sdk.pythonSdk
import com.jetbrains.python.statistics.modules
import java.util.regex.Pattern

Expand Down Expand Up @@ -348,7 +351,12 @@ fun validateConfig(pyClass: PyClass): List<PsiElement>? {
return results
}

fun getConfig(pyClass: PyClass, context: TypeEvalContext, setDefault: Boolean, pydanticVersion: KotlinVersion? = null): HashMap<String, Any?> {
fun getConfig(
pyClass: PyClass,
context: TypeEvalContext,
setDefault: Boolean,
pydanticVersion: KotlinVersion? = null,
): HashMap<String, Any?> {
val config = hashMapOf<String, Any?>()
val version = pydanticVersion ?: PydanticVersionService.getVersion(pyClass.project, context)
pyClass.getAncestorClasses(context)
Expand Down
15 changes: 10 additions & 5 deletions src/com/koxudaxi/pydantic/PydanticAnnotator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ class PydanticAnnotator : PyAnnotator() {
private fun annotatePydanticModelCallableExpression(pyCallExpression: PyCallExpression) {
val context = TypeEvalContext.userInitiated(pyCallExpression.project, pyCallExpression.containingFile)
val pyClass = getPydanticPyClass(pyCallExpression, context) ?: return
val unFilledArguments = getPydanticUnFilledArguments(pyClass, pyCallExpression, pydanticTypeProvider, context).nullize()
val unFilledArguments =
getPydanticUnFilledArguments(pyClass, pyCallExpression, pydanticTypeProvider, context).nullize()
?: return
holder.newSilentAnnotation(HighlightSeverity.INFORMATION).withFix(PydanticInsertArgumentsQuickFix(false)).create()
holder.newSilentAnnotation(HighlightSeverity.INFORMATION).withFix(PydanticInsertArgumentsQuickFix(false))
.create()
unFilledArguments.filter { it.required }.nullize() ?: return
val highlight = when {
isSubClassOfBaseSetting(pyClass, context) || pyCallExpression.arguments.any {(it as? PyStarArgument)?.isKeyword == true} -> HighlightSeverity.INFORMATION
isSubClassOfBaseSetting(pyClass,
context) || pyCallExpression.arguments.any { (it as? PyStarArgument)?.isKeyword == true } -> HighlightSeverity.INFORMATION
else -> HighlightSeverity.WARNING
}
holder.newSilentAnnotation(highlight).withFix(PydanticInsertArgumentsQuickFix(true)).range(TextRange.from(pyCallExpression.textOffset + pyCallExpression.textLength - 1,1)).create()
holder.newSilentAnnotation(HighlightSeverity.INFORMATION).withFix(PydanticInsertArgumentsQuickFix(true)).range(TextRange.from(pyCallExpression.textOffset,pyCallExpression.textLength - 2)).create()
holder.newSilentAnnotation(highlight).withFix(PydanticInsertArgumentsQuickFix(true))
.range(TextRange.from(pyCallExpression.textOffset + pyCallExpression.textLength - 1, 1)).create()
holder.newSilentAnnotation(HighlightSeverity.INFORMATION).withFix(PydanticInsertArgumentsQuickFix(true))
.range(TextRange.from(pyCallExpression.textOffset, pyCallExpression.textLength - 2)).create()
}
}
307 changes: 190 additions & 117 deletions src/com/koxudaxi/pydantic/PydanticCompletionContributor.kt

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions src/com/koxudaxi/pydantic/PydanticConfigPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

public class PydanticConfigPanel {

private JPanel configPanel;
private JCheckBox initTypedCheckBox;
private JTextPane ifEnabledIncludeTheTextPane;
private JCheckBox warnUntypedFieldsCheckBox;
private JTextPane ifEnabledRaiseATextPane;
private JTextPane textPane1;
PydanticConfigPanel(Project project) {
PydanticConfigService pydanticConfigService = PydanticConfigService.Companion.getInstance(project);

Expand All @@ -33,13 +39,6 @@ public class PydanticConfigPanel {
setHyperlinkHtml(this.textPane1, "See <a href=\"https://koxudaxi.github.io/pydantic-pycharm-plugin/\">documentation</a> for more details.</p>");
}

private JPanel configPanel;
private JCheckBox initTypedCheckBox;
private JTextPane ifEnabledIncludeTheTextPane;
private JCheckBox warnUntypedFieldsCheckBox;
private JTextPane ifEnabledRaiseATextPane;
private JTextPane textPane1;

public Boolean getInitTyped() {
return initTypedCheckBox.isSelected();
}
Expand Down
2 changes: 1 addition & 1 deletion src/com/koxudaxi/pydantic/PydanticConfigurable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class PydanticConfigurable internal constructor(project: Project) : Configurable

override fun isModified(): Boolean {
if (configPanel.initTyped == null || configPanel.warnUntypedFields == null) return false
return (pydanticConfigService.initTyped != configPanel.initTyped) ||
return (pydanticConfigService.initTyped != configPanel.initTyped) ||
(pydanticConfigService.warnUntypedFields != configPanel.warnUntypedFields)
}

Expand Down
3 changes: 2 additions & 1 deletion src/com/koxudaxi/pydantic/PydanticDataclassTypeProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package com.koxudaxi.pydantic
import com.intellij.psi.PsiElement
import com.jetbrains.python.codeInsight.stdlib.PyDataclassTypeProvider
import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.impl.*
import com.jetbrains.python.psi.impl.PyCallExpressionImpl
import com.jetbrains.python.psi.impl.PyCallExpressionNavigator
import com.jetbrains.python.psi.types.*

/**
Expand Down
30 changes: 22 additions & 8 deletions src/com/koxudaxi/pydantic/PydanticDynamicModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import com.jetbrains.python.psi.types.PyCallableParameter
import com.jetbrains.python.psi.types.PyClassLikeType
import com.jetbrains.python.psi.types.TypeEvalContext

class PydanticDynamicModel(astNode: ASTNode, val baseModel: PyClass, val attributes: Map<String, Attribute>) : PyClassImpl(astNode) {
val members: List<PyCustomMember> = attributes.values.map { it.pyCustomMember }
private val memberResolver: Map<String, PyElement> = attributes.entries.filterNot { it.value.isInAncestor } .associate { it.key to it.value.pyElement }
class PydanticDynamicModel(astNode: ASTNode, val baseModel: PyClass, val attributes: Map<String, Attribute>) :
PyClassImpl(astNode) {
val members: List<PyCustomMember> = attributes.values.map { it.pyCustomMember }
private val memberResolver: Map<String, PyElement> =
attributes.entries.filterNot { it.value.isInAncestor }.associate { it.key to it.value.pyElement }

fun resolveMember(name: String): PyElement? = memberResolver[name]

Expand All @@ -22,17 +24,29 @@ class PydanticDynamicModel(astNode: ASTNode, val baseModel: PyClass, val attribu
mutableListOf(it)
} ?: mutableListOf()
}
data class Attribute(val pyCallableParameter: PyCallableParameter, val pyCustomMember: PyCustomMember, val pyElement: PyElement, val isInAncestor: Boolean)

data class Attribute(
val pyCallableParameter: PyCallableParameter,
val pyCustomMember: PyCustomMember,
val pyElement: PyElement,
val isInAncestor: Boolean,
)

companion object {
fun createAttribute(name: String, parameter: PyCallableParameter, originalPyExpression: PyExpression, context: TypeEvalContext, isInAncestor: Boolean): Attribute {
fun createAttribute(
name: String,
parameter: PyCallableParameter,
originalPyExpression: PyExpression,
context: TypeEvalContext,
isInAncestor: Boolean,
): Attribute {
val type = parameter.getType(context)
return Attribute(parameter,
PyCustomMember(name, null) { type }
PyCustomMember(name, null) { type }
.toPsiElement(originalPyExpression)
.withIcon(AllIcons.Nodes.Field),
originalPyExpression,
isInAncestor
originalPyExpression,
isInAncestor
)
}
}
Expand Down
21 changes: 16 additions & 5 deletions src/com/koxudaxi/pydantic/PydanticDynamicModelMemberProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,30 @@ package com.koxudaxi.pydantic
import com.intellij.psi.PsiElement
import com.jetbrains.python.codeInsight.PyCustomMember
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.types.*
import com.jetbrains.python.psi.types.PyClassMembersProviderBase
import com.jetbrains.python.psi.types.PyClassType
import com.jetbrains.python.psi.types.TypeEvalContext

class PydanticDynamicModelMemberProvider : PyClassMembersProviderBase() {
override fun resolveMember(type: PyClassType, name: String, location: PsiElement?, resolveContext: PyResolveContext): PsiElement? {
val pyClass = type.pyClass
override fun resolveMember(
type: PyClassType,
name: String,
location: PsiElement?,
resolveContext: PyResolveContext,
): PsiElement? {
val pyClass = type.pyClass
if (pyClass is PydanticDynamicModel && !type.isDefinition)
pyClass.resolveMember(name)?.let { return it }
return super.resolveMember(type, name, location, resolveContext)
}

override fun getMembers(clazz: PyClassType?, location: PsiElement?, context: TypeEvalContext): MutableCollection<PyCustomMember> {
override fun getMembers(
clazz: PyClassType?,
location: PsiElement?,
context: TypeEvalContext,
): MutableCollection<PyCustomMember> {
if (clazz == null || clazz.isDefinition) return mutableListOf()
val pyClass = clazz.pyClass
val pyClass = clazz.pyClass
return if (pyClass is PydanticDynamicModel) {
pyClass.members.toMutableList()
} else {
Expand Down
38 changes: 20 additions & 18 deletions src/com/koxudaxi/pydantic/PydanticFieldRenameFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class PydanticFieldRenameFactory : AutomaticRenamerFactory {
if (isPydanticModel(pyClass, true)) return true
}
is PyKeywordArgument -> {
val pyClass = getPyClassByPyKeywordArgument(element, TypeEvalContext.codeAnalysis(element.project, element.containingFile)) ?: return false
val pyClass = getPyClassByPyKeywordArgument(element,
TypeEvalContext.codeAnalysis(element.project, element.containingFile)) ?: return false
if (isPydanticModel(pyClass, true)) return true
}
}
Expand Down Expand Up @@ -53,17 +54,18 @@ class PydanticFieldRenameFactory : AutomaticRenamerFactory {
is PyTargetExpression ->
element.name?.let { name ->
element.containingClass
?.let { pyClass ->
addAllElement(pyClass, name, added)
}
?.let { pyClass ->
addAllElement(pyClass, name, added)
}
suggestAllNames(name, newName)
}
is PyKeywordArgument ->
element.name?.let { name ->
getPyClassByPyKeywordArgument(element, TypeEvalContext.userInitiated(element.project, element.containingFile))
?.let { pyClass ->
addAllElement(pyClass, name, added)
}
getPyClassByPyKeywordArgument(element,
TypeEvalContext.userInitiated(element.project, element.containingFile))
?.let { pyClass ->
addAllElement(pyClass, name, added)
}
suggestAllNames(name, newName)
}
}
Expand All @@ -74,12 +76,12 @@ class PydanticFieldRenameFactory : AutomaticRenamerFactory {
addClassAttributes(pyClass, elementName)
addKeywordArguments(pyClass, elementName)
pyClass.getAncestorClasses(null)
.filter { isPydanticModel(it, true) && !added.contains(it) }
.forEach { addAllElement(it, elementName, added) }
.filter { isPydanticModel(it, true) && !added.contains(it) }
.forEach { addAllElement(it, elementName, added) }

PyClassInheritorsSearch.search(pyClass, true)
.filterNot { added.contains(it) }
.forEach { addAllElement(it, elementName, added) }
.filterNot { added.contains(it) }
.forEach { addAllElement(it, elementName, added) }
}

private fun addClassAttributes(pyClass: PyClass, elementName: String) {
Expand All @@ -90,12 +92,12 @@ class PydanticFieldRenameFactory : AutomaticRenamerFactory {
private fun addKeywordArguments(pyClass: PyClass, elementName: String) {
ReferencesSearch.search(pyClass as PsiElement).forEach { psiReference ->
PsiTreeUtil.getParentOfType(psiReference.element, PyCallExpression::class.java)
?.let { callee ->
callee.arguments
.filterIsInstance<PyKeywordArgument>()
.filter { it.name == elementName }
.forEach { myElements.add(it) }
}
?.let { callee ->
callee.arguments
.filterIsInstance<PyKeywordArgument>()
.filter { it.name == elementName }
.forEach { myElements.add(it) }
}
}
}

Expand Down
Loading

0 comments on commit 28abc47

Please sign in to comment.