├── testData ├── mock │ ├── pydanticv2 │ │ ├── _internal │ │ │ ├── __init__.py │ │ │ └── _config │ │ │ │ └── __init__.py │ │ ├── version.py │ │ ├── deprecated │ │ │ ├── __init__.py │ │ │ └── class_validators.py │ │ ├── v1 │ │ │ ├── __init__.py │ │ │ ├── fields.py │ │ │ └── main.py │ │ ├── root_model.py │ │ ├── functional_validators.py │ │ ├── config.py │ │ ├── __init__.py │ │ └── fields.py │ ├── pydanticv0 │ │ ├── dataclasses.py │ │ ├── main.py │ │ ├── env_settings.py │ │ ├── class_validators.py │ │ ├── version.py │ │ ├── __init__.py │ │ └── schema.py │ ├── pydanticv1 │ │ ├── dataclasses.py │ │ ├── networks.py │ │ ├── env_settings.py │ │ ├── class_validators.py │ │ ├── version.py │ │ ├── __init__.py │ │ ├── types.py │ │ ├── fields.py │ │ └── main.py │ ├── pydantic_settingsv2 │ │ ├── __init__.py │ │ └── main.py │ ├── stub │ │ ├── builtins.py │ │ ├── sqlmodel │ │ │ └── __init__.py │ │ ├── dataclasses.py │ │ └── typing.py │ └── pydanticv18 │ │ ├── networks.py │ │ ├── class_validators.py │ │ ├── version.py │ │ ├── __init__.py │ │ ├── types.py │ │ ├── env_settings.py │ │ ├── fields.py │ │ ├── generics.py │ │ ├── main.py │ │ └── dataclasses.py ├── MockSdk │ └── bin │ │ └── python ├── completion │ ├── parameterNoType.py │ ├── string.py │ ├── unResolveInstance.py │ ├── assignedInstanceWithImport.py │ ├── assignedString.py │ ├── instanceUnResolve.py │ ├── nestedClass.py │ ├── importedInstance.py │ ├── config.py │ ├── importedAssignedInstance.py │ ├── instancePythonFunction.py │ ├── fieldCustomRoot.py │ ├── definedNestedClass.py │ ├── baseSetting.py │ ├── keywordArgumentPythonClass.py │ ├── fieldOverride.py │ ├── instanceParent.py │ ├── keywordArgumentPythonFunction.py │ ├── pythonClass.py │ ├── keywordArgumentAssignValue.py │ ├── keywordArgumentCustomRoot.py │ ├── keywordArgumentInserted.py │ ├── keywordArgumentParent.py │ ├── methodSelf.py │ ├── configDefined.py │ ├── class.py │ ├── instanceBroken.py │ ├── instancePythonClass.py │ ├── classFields.py │ ├── classMethodCls.py │ ├── instance.py │ ├── keywordArgument.py │ ├── keywordArgumentDot.py │ ├── parameterAnnotation.py │ ├── parameterAnnotationPythonClass.py │ ├── field.py │ ├── instanceParentIsPythonClass.py │ ├── keywordArgumentDotName.py │ ├── parameterDefaultValue.py │ ├── assignedClass.py │ ├── assignedInstance.py │ ├── assignedInstancePythonClass.py │ ├── classValidatorCls.py │ ├── parameterAnnotationType.py │ ├── keywordArgumentIgnore.py │ ├── parameterAnnotationUnion.py │ ├── parameterAnnotationUnionPythonClass.py │ ├── conlist.py │ ├── fieldOptional.py │ ├── parameterAnnotationTypeKeywordArgument.py │ ├── classInitMethod.py │ ├── fieldUnion.py │ ├── keywordArgumentInitPosition.py │ ├── subscriptionClass.py │ ├── keywordArgumentInitKwargs.py │ ├── keywordArgumentAllowPopulationByFieldName.py │ ├── keywordArgumentAllowPopulationByFieldNameFalse.py │ ├── keywordArgumentInitArgsKwargs.py │ ├── keywordArgumentAllowPopulationByFieldNameChild.py │ ├── keywordArgumentAllowPopulationByFieldNameParent.py │ ├── keywordArgumentInitArgsKwargsDisable.py │ ├── keywordArgumentFieldAnnotated.py │ ├── keywordArgumentAllowPopulationByFieldNameMultipleInheritance.py │ ├── fieldAnnotated.py │ ├── fieldIgnore.py │ ├── fieldField.py │ ├── fieldSchemaField.py │ ├── fieldSchema.py │ ├── keywordArgumentSchemaField.py │ ├── keywordArgumentSchema.py │ └── dataclassKeywordArgument.py ├── initializer │ ├── pyprojecttomlempty │ │ └── pyproject.toml │ ├── mypyiniempty │ │ └── mypy.ini │ ├── pyprojecttomldisable │ │ └── pyproject.toml │ ├── mypyini │ │ └── mypy.ini │ ├── mypyinibroken │ │ └── mypy.ini │ ├── mypyinichange │ │ └── mypy.ini │ ├── pyprojecttomlchange │ │ └── pyproject.toml │ ├── pyprojecttomldefault │ │ └── pyproject.toml │ └── pyprojecttoml │ │ └── pyproject.toml ├── ignoreinspection │ ├── pythonFunction.py │ ├── pythonMethod.py │ ├── baseModel.py │ ├── validator.py │ ├── validatorField.py │ ├── decoratorField.py │ ├── validatorModeAfter.py │ ├── validatorDataclass.py │ ├── validatorFullPath.py │ └── pythonDecorator.py ├── search │ ├── unResolve.py │ ├── keywordArgumentUnResolve.py │ ├── fieldUnResolve.py │ ├── pythonClassChildKeywordArgument.py │ ├── keywordArgument.py │ ├── childKeywordArgument.py │ ├── keywordArgumentInFunctionByField.py │ ├── pythonClassChildField.py │ ├── childField.py │ ├── field.py │ ├── methodLocalVariable.py │ ├── parentKeywordArgument.py │ ├── grandChildKeywordArgumentNotFound.py │ ├── parameter.py │ ├── grandChildKeywordArgument.py │ ├── childrenKeywordArgument.py │ ├── parentField.py │ ├── childrenField.py │ ├── grandChildField.py │ ├── multipleInheritanceField.py │ ├── grandChildFieldWithPythonClass.py │ ├── grandChildKeywordArgumentWithPythonClass.py │ ├── multipleInheritanceKeywordArgument.py │ └── multipleInheritedField.py ├── typeinspection │ ├── unResolve.py │ ├── field.py │ ├── duplicateField.py │ ├── fieldDefaultValue.py │ ├── fieldEllipsis.py │ ├── baseSetting.py │ ├── fieldInherit.py │ ├── fieldOptionalDefaultValue.py │ ├── fieldOptional.py │ ├── fieldInvalid.py │ ├── skipMember.py │ ├── fieldUnion.py │ ├── fieldDefaultValueInvalid.py │ ├── initAncestor.py │ ├── ignoreInitArguments.py │ ├── fieldOptionalDefaultValueInvalid.py │ ├── fieldOptionalInvalid.py │ ├── initInvalid.py │ ├── fieldSchema.py │ ├── initAncestorInvalid.py │ ├── init.py │ ├── fieldUnionOperatorInvalid.py │ ├── fieldUnionInvalid.py │ ├── fieldBroken.py │ ├── allowPopulationByFieldNameAlias.py │ ├── fieldSchemaInvalid.py │ ├── fieldField.py │ └── fieldFieldInvalid.py ├── completionv2 │ ├── configDict.py │ ├── baseSettingPydanticSettings.py │ ├── v1CompatKeywordArgument.py │ ├── v1CompatInstance.py │ ├── keywordArgumentPopulateByName.py │ ├── validatorField.py │ └── fieldAnnotated.py ├── refactor │ ├── renameUnResolve.py │ ├── renameUnResolve_after.py │ ├── renamePythonClass.py │ ├── renameUnResolveTargetExpression.py │ ├── renameUnResolveTargetExpression_after.py │ ├── renamer.py │ ├── renamePythonFunction.py │ ├── renamePythonClassKeywordArgument.py │ ├── renamePythonFunctionKeywordArgument.py │ ├── renameMethodLocalVariable_after.py │ ├── renameMethodLocalVariable.py │ ├── renameKeywordArgumentDataclass.py │ ├── renameKeywordArgumentDataclass_after.py │ ├── renameKeywordArgument_after.py │ ├── renameKeywordArgument.py │ ├── renameGrandChildFieldWithPythonClass.py │ ├── renameGrandChildFieldWithPythonClass_after.py │ ├── renameFieldDataclass.py │ ├── renameFieldDataclass_after.py │ ├── renameField_after.py │ └── renameField.py ├── inspection │ ├── pythonClass.py │ ├── acceptsOnlyKeywordArgumentsKeywordArgument.py │ ├── acceptsOnlyKeywordArgumentsDoubleStarArgument.py │ ├── callTypeWithSelf.py │ ├── acceptsOnlyKeywordFunction.py │ ├── configDuplicate.py │ ├── acceptsOnlyKeywordArgumentsInit.py │ ├── warnUntypedFieldsDisable.py │ ├── acceptsOnlyKeywordArgumentsSingleStarArgument.py │ ├── warnUntypedFields.py │ ├── kwargConfig.py │ ├── acceptsOnlyKeywordArguments.py │ ├── customRoot.py │ ├── extra.py │ ├── validatorSelf.py │ ├── ormMode.py │ ├── readOnlyProperty.py │ └── rootValidatorSelf.py ├── regex │ ├── field.py │ ├── fieldDefault.py │ ├── constr.py │ ├── constrMinLength.py │ ├── fieldTitle.py │ └── otherFunc.py ├── inspectionv2 │ ├── privateFieldsBaseModelAlias.py │ ├── privateFieldDataclassTransform.py │ ├── frozenClassArgument.py │ ├── extra.py │ ├── validators.py │ ├── modelAttribute.py │ ├── readOnlyPropertyFrozenConfig.py │ ├── validatorSelf.py │ ├── customRoot.py │ ├── readOnlyPropertyFrozenConfigDict.py │ └── validatorField.py ├── completionv18 │ ├── overrideInitField.py │ ├── insertedArgument.py │ ├── overrideInitKeywordArgument.py │ ├── aliasNameKeywordArgument.py │ ├── sqlModelClassCompletion.py │ ├── validatorField.py │ ├── genericField.py │ └── genericKeywordArgument.py ├── typecheckerinspection │ ├── class.py │ ├── parsableTypeDisable.py │ ├── acceptableTypeDisable.py │ ├── acceptableTypeInvalid.py │ ├── parsableTypeInvalid.py │ ├── parsableType.py │ ├── parsableTypeWeakWarning.py │ ├── acceptableTypeWarning.py │ ├── fieldImportTyping.py │ ├── field.py │ ├── acceptableType.py │ ├── parsableTypeCollection.py │ ├── noDuplicateWarning.py │ └── fieldImportTypingInvalid.py ├── typeinspectionv2 │ ├── baseSettingPydanticSettings.py │ ├── populateByNameAliasEdge.py │ └── populateByNameAlias.py ├── pynesteddecoratorsinspectionsuppressor │ └── modelValidator.py ├── insertargumentsquickfix │ ├── noArguments.py │ ├── partArguments.py │ ├── lastCharOnlyRequired.py │ ├── noArgumentsOnlyRequired.py │ ├── lastCharOnlyRequired_after.py │ ├── nestedOtherObject.py │ ├── nestedPartArguments.py │ ├── noArgumentsOnlyRequired_after.py │ ├── noArguments_after.py │ ├── partArgumentsOnlyRequired.py │ ├── partArguments_after.py │ ├── partArgumentsOnlyRequired_after.py │ ├── nestedPartArguments_after.py │ ├── nestedOtherObject_after.py │ ├── lastChar.py │ ├── lastChar_after.py │ ├── dataclass.py │ └── dataclass_after.py ├── typeinspectionv18 │ ├── baseSetting.py │ ├── sqlModel.py │ └── overrideInit.py ├── inspectionv18 │ ├── validatorField.py │ ├── kwargConfig.py │ ├── configDuplicate.py │ ├── readOnlyPropertyFrozen.py │ ├── readOnlyProperty.py │ └── defaultFactory.py └── completionv0 │ ├── fieldSchema.py │ └── keywordArgumentSchema.py ├── requirements.txt ├── docs ├── demo1.gif ├── inspection1.png ├── settings1.png ├── typecheck1.png ├── search_plugin.png ├── init_arguments.png ├── parsable-type1.png ├── ignore_init_arguments.png ├── ignore-init-keyword-arguments.md ├── development.md ├── mypy-compatible.md ├── install.md └── ignore-init-arguments.md ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── resources ├── inspectionDescriptions │ ├── PydanticInspection.html │ └── PydanticTypeCheckerInspection.html └── META-INF │ ├── pluginIcon.svg │ └── python-common.xml ├── NOTICE.txt ├── settings.gradle.kts ├── qodana.yml ├── testSrc └── com │ ├── koxudaxi │ └── pydantic │ │ ├── PydanticPyNestedDecoratorsInspectionSuppressorTest.kt │ │ ├── PydanticInspectionBase.kt │ │ ├── PydanticTypeInspectionV2Test.kt │ │ ├── PydanticInspectionV18Test.kt │ │ ├── PydanticTypeInspectionV18Test.kt │ │ ├── PydanticInspectionV2Test.kt │ │ ├── PydanticRegexTest.kt │ │ ├── PydanticInsertArgumentsQuickFixTest.kt │ │ └── PydanticPythonPackageManagementListenerTest.kt │ └── jetbrains │ └── python │ └── PythonTestUtil.kt ├── src └── com │ └── koxudaxi │ └── pydantic │ ├── PydanticDynamicModelClassType.kt │ ├── PydanticValidatorFieldReference.kt │ ├── PydanticIgnoreInspection.kt │ ├── PydanticDataclassInspectionSuppressor.kt │ ├── PydanticConfigurable.kt │ ├── PydanticDataclassTypeProvider.kt │ ├── PydanticDynamicModelMemberProvider.kt │ ├── PydanticPyNestedDecoratorsInspectionSuppressor.kt │ ├── PydanticSdkChangeWatcher.kt │ ├── PydanticConfigService.kt │ └── PydanticRegexInjector.kt ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── docs.yml │ └── run-ui-tests.yml ├── .gitignore ├── .idea └── icon.svg ├── mkdocs.yml ├── .run ├── Run IDE for UI Tests.run.xml ├── Run IDE with Plugin.run.xml ├── Run Plugin Tests.run.xml ├── Run Qodana.run.xml └── Run Plugin Verification.run.xml ├── LICENSE └── gradle.properties /testData/mock/pydanticv2/_internal/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs==1.5.3 2 | mkdocs-material==9.5.18 -------------------------------------------------------------------------------- /testData/mock/pydanticv2/version.py: -------------------------------------------------------------------------------- 1 | VERSION = '2.0.0.dev0' -------------------------------------------------------------------------------- /testData/MockSdk/bin/python: -------------------------------------------------------------------------------- 1 | # placeholder for python interpreter 2 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/dataclasses.py: -------------------------------------------------------------------------------- 1 | def dataclass(): 2 | pass -------------------------------------------------------------------------------- /testData/mock/pydanticv1/dataclasses.py: -------------------------------------------------------------------------------- 1 | def dataclass(): 2 | pass -------------------------------------------------------------------------------- /testData/completion/parameterNoType.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def get_a(a): 4 | a. -------------------------------------------------------------------------------- /testData/initializer/pyprojecttomlempty/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.others] 2 | abc = "123" -------------------------------------------------------------------------------- /testData/mock/pydantic_settingsv2/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import BaseSettings 2 | 3 | -------------------------------------------------------------------------------- /testData/mock/stub/builtins.py: -------------------------------------------------------------------------------- 1 | from typing import Sequence 2 | class str(Sequence): ... -------------------------------------------------------------------------------- /testData/ignoreinspection/pythonFunction.py: -------------------------------------------------------------------------------- 1 | 2 | def validate_a(cls): 3 | pass 4 | -------------------------------------------------------------------------------- /docs/demo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/demo1.gif -------------------------------------------------------------------------------- /testData/completion/string.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | 6 | '1'. -------------------------------------------------------------------------------- /testData/completion/unResolveInstance.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | A(). -------------------------------------------------------------------------------- /testData/mock/pydanticv2/deprecated/__init__.py: -------------------------------------------------------------------------------- 1 | from class_validators import validator, root_validator -------------------------------------------------------------------------------- /docs/inspection1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/inspection1.png -------------------------------------------------------------------------------- /docs/settings1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/settings1.png -------------------------------------------------------------------------------- /docs/typecheck1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/typecheck1.png -------------------------------------------------------------------------------- /testData/initializer/mypyiniempty/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | 3 | follow_imports = silent 4 | strict_optional = True -------------------------------------------------------------------------------- /testData/mock/pydanticv1/networks.py: -------------------------------------------------------------------------------- 1 | class AnyUrl(str): 2 | pass 3 | class HttpUrl(AnyUrl): 4 | pass -------------------------------------------------------------------------------- /testData/mock/pydanticv18/networks.py: -------------------------------------------------------------------------------- 1 | class AnyUrl(str): 2 | pass 3 | class HttpUrl(AnyUrl): 4 | pass -------------------------------------------------------------------------------- /docs/search_plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/search_plugin.png -------------------------------------------------------------------------------- /testData/completion/assignedInstanceWithImport.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from .instance import A 4 | 5 | a = A() 6 | a. -------------------------------------------------------------------------------- /testData/completion/assignedString.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | 6 | a='1' 7 | a. -------------------------------------------------------------------------------- /testData/completion/instanceUnResolve.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | a = b 5 | 6 | a. -------------------------------------------------------------------------------- /testData/search/unResolve.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | A(abc=int(123)) 7 | -------------------------------------------------------------------------------- /testData/typeinspection/unResolve.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | A(a=int(123)) 7 | -------------------------------------------------------------------------------- /docs/init_arguments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/init_arguments.png -------------------------------------------------------------------------------- /docs/parsable-type1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/parsable-type1.png -------------------------------------------------------------------------------- /testData/completion/nestedClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | -------------------------------------------------------------------------------- /testData/completionv2/configDict.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | m -------------------------------------------------------------------------------- /testData/refactor/renameUnResolve.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | A(abc=int(123)) 7 | -------------------------------------------------------------------------------- /testData/refactor/renameUnResolve_after.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | A(abc=int(123)) 7 | -------------------------------------------------------------------------------- /testData/completion/importedInstance.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from .instance import A 4 | 5 | A(). -------------------------------------------------------------------------------- /testData/mock/pydanticv0/main.py: -------------------------------------------------------------------------------- 1 | class BaseModel: 2 | class Config: 3 | pass 4 | 5 | ___slots__ = () 6 | -------------------------------------------------------------------------------- /docs/ignore_init_arguments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/docs/ignore_init_arguments.png -------------------------------------------------------------------------------- /testData/inspection/pythonClass.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A: 5 | a: str 6 | 7 | 8 | A() 9 | -------------------------------------------------------------------------------- /testData/ignoreinspection/pythonMethod.py: -------------------------------------------------------------------------------- 1 | 2 | class A: 3 | a: str 4 | 5 | def validate_a(cls): 6 | pass 7 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/env_settings.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel 2 | 3 | 4 | class BaseSettings(BaseModel): 5 | pass 6 | -------------------------------------------------------------------------------- /testData/mock/pydanticv1/env_settings.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel 2 | 3 | 4 | class BaseSettings(BaseModel): 5 | pass 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koxudaxi/pydantic-pycharm-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /testData/completion/config.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | class Config: 6 | -------------------------------------------------------------------------------- /testData/completion/importedAssignedInstance.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from .assignedInstance import a 4 | 5 | a. -------------------------------------------------------------------------------- /resources/inspectionDescriptions/PydanticInspection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This inspection checks Pydantic models. 4 | 5 | -------------------------------------------------------------------------------- /testData/completion/instancePythonFunction.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | def a(): 7 | pass 8 | 9 | a(). -------------------------------------------------------------------------------- /testData/completion/fieldCustomRoot.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | __root__: str 6 | 7 | A(). -------------------------------------------------------------------------------- /testData/mock/pydantic_settingsv2/main.py: -------------------------------------------------------------------------------- 1 | from pydantic.main import BaseModel 2 | 3 | 4 | class BaseSettings(BaseModel): 5 | pass 6 | 7 | -------------------------------------------------------------------------------- /testData/refactor/renamePythonClass.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A: 5 | abc: str 6 | 7 | 8 | A(abc='abc') 9 | -------------------------------------------------------------------------------- /testData/refactor/renameUnResolveTargetExpression.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | def x(): 7 | abc=int(123) 8 | -------------------------------------------------------------------------------- /testData/refactor/renameUnResolveTargetExpression_after.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | def x(): 7 | abc=int(123) 8 | -------------------------------------------------------------------------------- /testData/refactor/renamer.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str 6 | 7 | 8 | A(abc='abc') 9 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | This software includes code from IntelliJ IDEA Community Edition 2 | Copyright (C) JetBrains s.r.o. 3 | https://www.jetbrains.com/idea/ 4 | -------------------------------------------------------------------------------- /testData/refactor/renamePythonFunction.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | def a(abc='abc'): 5 | pass 6 | 7 | a(abc='abc') 8 | -------------------------------------------------------------------------------- /testData/regex/field.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class Model(BaseModel): 5 | abc: str = Field(regex='[^a-zA-Z]+') 6 | -------------------------------------------------------------------------------- /testData/regex/fieldDefault.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class Model(BaseModel): 5 | abc: str = Field('[^a-zA-Z]+') 6 | -------------------------------------------------------------------------------- /testData/completion/definedNestedClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | class Config: 6 | pass 7 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/v1/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel, BaseConfig, Extra, GetterDict, json, create_model 2 | from .fields import Field, Schema 3 | -------------------------------------------------------------------------------- /testData/refactor/renamePythonClassKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A: 5 | abc: str 6 | 7 | 8 | A(abc='abc') 9 | -------------------------------------------------------------------------------- /testData/regex/constr.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, constr 2 | 3 | 4 | class Model(BaseModel): 5 | abc: constr(regex='[^a-zA-Z]+') = None 6 | -------------------------------------------------------------------------------- /testData/regex/constrMinLength.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, constr 2 | 3 | 4 | class Model(BaseModel): 5 | abc: constr(min_length=1) = None 6 | -------------------------------------------------------------------------------- /testData/regex/fieldTitle.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class Model(BaseModel): 5 | abc: str = Field(title='[^a-zA-Z]+') 6 | -------------------------------------------------------------------------------- /testData/inspectionv2/privateFieldsBaseModelAlias.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel as BM 2 | 3 | 4 | class Model(BM): 5 | _value: int 6 | 7 | 8 | Model() 9 | -------------------------------------------------------------------------------- /testData/mock/stub/sqlmodel/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import SQLModel as SQLModel 2 | from .main import Field as Field 3 | from .main import Relationship as Relationship -------------------------------------------------------------------------------- /testData/refactor/renamePythonFunctionKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | def a(abc='abc'): 5 | pass 6 | 7 | a(abc='abc') 8 | -------------------------------------------------------------------------------- /testData/typeinspection/field.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | 10 | A(a=int(123)) 11 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" 3 | } 4 | 5 | rootProject.name = "pydantic-pycharm-plugin" 6 | -------------------------------------------------------------------------------- /testData/inspectionv2/privateFieldDataclassTransform.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Model(BaseModel): 5 | _value: int 6 | 7 | 8 | Model() 9 | -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordArgumentsKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | 8 | A(a='abc') 9 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/class_validators.py: -------------------------------------------------------------------------------- 1 | def validator(*args: str, **kwargs: str): 2 | pass 3 | 4 | 5 | def root_validator(_func=None, *, pre=False): 6 | pass 7 | -------------------------------------------------------------------------------- /testData/mock/pydanticv1/class_validators.py: -------------------------------------------------------------------------------- 1 | def validator(*args: str, **kwargs: str): 2 | pass 3 | 4 | 5 | def root_validator(_func=None, *, pre=False): 6 | pass 7 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/class_validators.py: -------------------------------------------------------------------------------- 1 | def validator(*args: str, **kwargs: str): 2 | pass 3 | 4 | 5 | def root_validator(_func=None, *, pre=False): 6 | pass 7 | -------------------------------------------------------------------------------- /testData/typeinspection/duplicateField.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class A(BaseModel): 6 | a: str 7 | a: int 8 | 9 | A(a=int(123)) 10 | -------------------------------------------------------------------------------- /testData/completion/baseSetting.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, BaseSettings 4 | 5 | 6 | class A(BaseSettings): 7 | b: str 8 | 9 | 10 | A(). 11 | -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordArgumentsDoubleStarArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | 8 | A(**{'a':'a'}) 9 | -------------------------------------------------------------------------------- /testData/search/keywordArgumentUnResolve.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | cde: str 6 | 7 | 8 | A(abc='cde') 9 | # count 0 -------------------------------------------------------------------------------- /testData/typeinspection/fieldDefaultValue.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a = int(123) 8 | 9 | 10 | A(a=int(123)) 11 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldEllipsis.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int = ... 8 | 9 | 10 | A(a=int(123)) 11 | -------------------------------------------------------------------------------- /testData/search/fieldUnResolve.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | cde: str # expected 6 | 7 | 8 | A(abc='cde') 9 | # count 1 -------------------------------------------------------------------------------- /testData/completionv2/baseSettingPydanticSettings.py: -------------------------------------------------------------------------------- 1 | from pydantic_settings import BaseSettings 2 | 3 | 4 | class A(BaseSettings): 5 | b: str 6 | 7 | 8 | A(). 9 | 10 | -------------------------------------------------------------------------------- /testData/ignoreinspection/baseModel.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | def validate_a(cls): 8 | pass 9 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentPythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A: 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | A() -------------------------------------------------------------------------------- /testData/inspection/callTypeWithSelf.py: -------------------------------------------------------------------------------- 1 | import pydantic 2 | 3 | 4 | class Model(pydantic.BaseModel): 5 | url: str 6 | 7 | def bla(self): 8 | assert type(self) 9 | 10 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/version.py: -------------------------------------------------------------------------------- 1 | class StrictVersion: 2 | def __init__(self, version): 3 | self.version = version 4 | 5 | 6 | __all__ = ['VERSION'] 7 | 8 | VERSION = '1.8' 9 | -------------------------------------------------------------------------------- /testData/typeinspection/baseSetting.py: -------------------------------------------------------------------------------- 1 | from builtins import * 2 | 3 | from pydantic import BaseModel, BaseSettings 4 | 5 | 6 | class A(BaseSettings): 7 | b: str 8 | 9 | 10 | A() -------------------------------------------------------------------------------- /testData/typeinspection/fieldInherit.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | class B(A): 10 | pass 11 | 12 | B(a=int(123)) 13 | -------------------------------------------------------------------------------- /testData/completion/fieldOverride.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | class B(A): 10 | a: str 11 | 12 | b = B() 13 | b. -------------------------------------------------------------------------------- /testData/completionv18/overrideInitField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | def __init__(self, xyz: int): 7 | pass 8 | 9 | A(). -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordFunction.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | 8 | def abc(a) -> A: 9 | pass 10 | 11 | abc('a') 12 | -------------------------------------------------------------------------------- /testData/regex/otherFunc.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, constr 2 | 3 | def other_func(regex): 4 | pass 5 | 6 | class Model(BaseModel): 7 | abc: str = other_func(regex='[^a-zA-Z]+') 8 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/class.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class A: 4 | def a(self, b: str): 5 | pass 6 | 7 | A().a(int(123)) 8 | 9 | -------------------------------------------------------------------------------- /testData/completion/instanceParent.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str 8 | 9 | class B(A): 10 | efg: str 11 | 12 | B(). -------------------------------------------------------------------------------- /testData/completion/keywordArgumentPythonFunction.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | def a( 7 | abc: str, 8 | cde: str, 9 | efg: str, 10 | ): pass 11 | 12 | a() -------------------------------------------------------------------------------- /testData/completion/pythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class B: 5 | hij: str 6 | 7 | class A: 8 | abc: str 9 | cde: str 10 | efg: str 11 | 12 | 13 | A. -------------------------------------------------------------------------------- /testData/completionv18/insertedArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class A(BaseModel): 5 | abc_efg: str = '123' 6 | abc_xyz: str = '456' 7 | 8 | A(abc_efg='789') 9 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/version.py: -------------------------------------------------------------------------------- 1 | class StrictVersion: 2 | def __init__(self, version): 3 | self.version = version 4 | 5 | 6 | __all__ = ['VERSION'] 7 | 8 | VERSION = StrictVersion('0.32') 9 | -------------------------------------------------------------------------------- /testData/mock/pydanticv1/version.py: -------------------------------------------------------------------------------- 1 | class StrictVersion: 2 | def __init__(self, version): 3 | self.version = version 4 | 5 | 6 | __all__ = ['VERSION'] 7 | 8 | VERSION = StrictVersion('1.0a1') 9 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAssignValue.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | 12 | A(abc=) -------------------------------------------------------------------------------- /testData/completion/keywordArgumentCustomRoot.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | __root__: str 8 | 9 | class B(A): 10 | hij: str 11 | 12 | A() -------------------------------------------------------------------------------- /testData/completion/keywordArgumentInserted.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | 12 | A(abc='abc',) -------------------------------------------------------------------------------- /testData/completion/keywordArgumentParent.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str 8 | 9 | class B(A): 10 | efg: str 11 | 12 | B() -------------------------------------------------------------------------------- /testData/completionv18/overrideInitKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | def __init__(self, xyz: int): 7 | pass 8 | 9 | A() -------------------------------------------------------------------------------- /testData/completion/methodSelf.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | 9 | 10 | def test(self): 11 | return self. 12 | 13 | 14 | -------------------------------------------------------------------------------- /testData/completionv2/v1CompatKeywordArgument.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | 12 | A() 13 | -------------------------------------------------------------------------------- /testData/typeinspectionv2/baseSettingPydanticSettings.py: -------------------------------------------------------------------------------- 1 | from builtins import * 2 | 3 | from pydantic_settings import BaseSettings 4 | 5 | 6 | class A(BaseSettings): 7 | b: str 8 | 9 | 10 | A() 11 | 12 | -------------------------------------------------------------------------------- /testData/completion/configDefined.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class A(BaseModel): 5 | class Config: 6 | allow_population_by_field_name = True 7 | max_anystr_length = 10 8 | -------------------------------------------------------------------------------- /testData/ignoreinspection/validator.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | @validator('a') 8 | def validate_a(cls): 9 | pass 10 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel 2 | from .class_validators import validator, root_validator 3 | from .schema import Schema 4 | from .fields import Field 5 | from .env_settings import BaseSettings -------------------------------------------------------------------------------- /testData/typeinspection/fieldOptionalDefaultValue.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: int = None 9 | 10 | 11 | A(a=int(123)) 12 | -------------------------------------------------------------------------------- /testData/completion/class.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | class B: 5 | hij: str 6 | 7 | class A(BaseModel, B): 8 | abc: str 9 | cde = 'abc' 10 | efg: str = 'abc' 11 | 12 | 13 | A. -------------------------------------------------------------------------------- /testData/completion/instanceBroken.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str a 7 | cde: str = s 8 | efg: 9 | 10 | class B(A): 11 | hij: str 12 | 13 | A(). -------------------------------------------------------------------------------- /testData/completion/instancePythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A: 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | class B(A): 12 | hij: str 13 | 14 | A(). -------------------------------------------------------------------------------- /testData/ignoreinspection/validatorField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | @validator('x') 8 | def validate_a(cls): 9 | pass 10 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldOptional.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: Optional[int] 9 | 10 | 11 | A(a=int(123)) 12 | A(a=None) 13 | -------------------------------------------------------------------------------- /testData/completion/classFields.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | B. -------------------------------------------------------------------------------- /testData/completion/classMethodCls.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | 9 | @classmethod 10 | def test(cls): 11 | return cls. 12 | 13 | 14 | -------------------------------------------------------------------------------- /testData/completion/instance.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | A(). -------------------------------------------------------------------------------- /testData/completion/keywordArgument.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | class B(A): 12 | hij: str 13 | 14 | A() -------------------------------------------------------------------------------- /testData/typeinspection/fieldInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: str 8 | 9 | 10 | A(a=int(123)) 11 | -------------------------------------------------------------------------------- /testData/typeinspection/skipMember.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | __init__: str 8 | 9 | 10 | class B(BaseModel): 11 | __new__: str 12 | 13 | 14 | A() 15 | B() 16 | -------------------------------------------------------------------------------- /qodana.yml: -------------------------------------------------------------------------------- 1 | # Qodana configuration: 2 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html 3 | 4 | version: 1.0 5 | profile: 6 | name: qodana.recommended 7 | exclude: 8 | - name: All 9 | paths: 10 | - .qodana 11 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentDot.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | class B(A): 12 | hij: str 13 | 14 | A(B.) -------------------------------------------------------------------------------- /testData/completion/parameterAnnotation.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str = 'abc' 8 | efg: str = 'abc' 9 | 10 | 11 | def get_a(a: A): 12 | a. -------------------------------------------------------------------------------- /testData/completion/parameterAnnotationPythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A: 6 | abc: str 7 | cde: str = 'abc' 8 | efg: str = 'abc' 9 | 10 | 11 | def get_a(a: A): 12 | a. -------------------------------------------------------------------------------- /testData/refactor/renameMethodLocalVariable_after.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc = "" 6 | 7 | @classmethod 8 | def do(cls): 9 | cde = "abc" 10 | assert cde 11 | -------------------------------------------------------------------------------- /testData/completion/field.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = ... 9 | hij = ... 10 | 11 | class B(A): 12 | hij: str 13 | 14 | A(). -------------------------------------------------------------------------------- /testData/completion/instanceParentIsPythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A: 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | class B(BaseModel, A): 12 | hij: str 13 | 14 | B(). -------------------------------------------------------------------------------- /testData/completion/keywordArgumentDotName.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str 9 | efg: str 10 | 11 | class B(A): 12 | hij: str 13 | 14 | A(B.hi) -------------------------------------------------------------------------------- /testData/completion/parameterDefaultValue.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str = 'abc' 8 | efg: str = 'abc' 9 | 10 | 11 | def get_a(a = A()): 12 | a. -------------------------------------------------------------------------------- /testData/completionv2/v1CompatInstance.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str = 'abc' 9 | efg: str = 'abc' 10 | 11 | 12 | a = A(abc='a') 13 | a. 14 | -------------------------------------------------------------------------------- /testData/refactor/renameMethodLocalVariable.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc = "" 6 | 7 | @classmethod 8 | def do(cls): 9 | abc = "abc" 10 | assert abc 11 | -------------------------------------------------------------------------------- /testData/search/pythonClassChildKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A: 5 | abc: str 6 | 7 | class B(A): 8 | abc: str 9 | 10 | 11 | A(abc='cde') 12 | B(abc='cde') 13 | # count 0 -------------------------------------------------------------------------------- /testData/typeinspection/fieldUnion.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: Union[int, str, None] 9 | 10 | 11 | A(a=int(123)) 12 | A(a=str('123')) 13 | A(a=None) -------------------------------------------------------------------------------- /testData/completion/assignedClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | a = A 14 | a() -------------------------------------------------------------------------------- /testData/completion/assignedInstance.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | a = A() 14 | a. -------------------------------------------------------------------------------- /testData/completion/assignedInstancePythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | 4 | 5 | class A: 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | a = A() 14 | a. -------------------------------------------------------------------------------- /testData/mock/stub/dataclasses.py: -------------------------------------------------------------------------------- 1 | class _MISSING_TYPE: 2 | pass 3 | MISSING = _MISSING_TYPE() 4 | 5 | def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, 6 | hash=None, compare=True, metadata=None): 7 | pass -------------------------------------------------------------------------------- /testData/search/keywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str 9 | 10 | 11 | A(abc='cde') 12 | B(abc='cde') 13 | # count 1 -------------------------------------------------------------------------------- /testData/typeinspection/fieldDefaultValueInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a = 'abc' 8 | 9 | 10 | A(a=int(123)) 11 | -------------------------------------------------------------------------------- /testData/completion/classValidatorCls.py: -------------------------------------------------------------------------------- 1 | , 2 | 3 | from pydantic import BaseModel, validator 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | 9 | @validator('abc') 10 | def test(cls): 11 | return cls. 12 | 13 | 14 | -------------------------------------------------------------------------------- /testData/ignoreinspection/decoratorField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | def deco(func): 4 | pass 5 | class A(BaseModel): 6 | a: str 7 | 8 | @deco('x') 9 | def validate_a(cls): 10 | pass 11 | -------------------------------------------------------------------------------- /testData/ignoreinspection/validatorModeAfter.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, model_validator 2 | 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | @model_validator(mode='after') 8 | def validate_a(self): 9 | pass 10 | -------------------------------------------------------------------------------- /testData/search/childKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str 6 | 7 | class B(A): 8 | abc: str # expected 9 | 10 | 11 | A(abc='cde') 12 | B(abc='cde') 13 | # count 1 -------------------------------------------------------------------------------- /testData/search/keywordArgumentInFunctionByField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | from typing import Type 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | def func(instance: A): 8 | instance(abc) 9 | ## count: 2 -------------------------------------------------------------------------------- /testData/search/pythonClassChildField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A: 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str # expected 9 | 10 | A(abc='cde') 11 | B(abc='cde') 12 | ## count: 2 -------------------------------------------------------------------------------- /testData/completionv18/aliasNameKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | efg: str = Field(alias='e-f-g') 7 | hij: str = Field(alias='klm') 8 | 9 | A() 10 | -------------------------------------------------------------------------------- /testData/refactor/renameKeywordArgumentDataclass.py: -------------------------------------------------------------------------------- 1 | from pydantic.dataclasses import dataclass 2 | 3 | @dataclass 4 | class A: 5 | abc: str 6 | 7 | @dataclass 8 | class B(A): 9 | abc: int 10 | 11 | A(abc='abc') 12 | B(abc='abc') 13 | -------------------------------------------------------------------------------- /testData/refactor/renameKeywordArgumentDataclass_after.py: -------------------------------------------------------------------------------- 1 | from pydantic.dataclasses import dataclass 2 | 3 | @dataclass 4 | class A: 5 | cde: str 6 | 7 | @dataclass 8 | class B(A): 9 | cde: int 10 | 11 | A(cde='abc') 12 | B(cde='abc') 13 | -------------------------------------------------------------------------------- /testData/search/childField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str # expected 9 | 10 | A(abc='cde') 11 | B(abc='cde') # expected 12 | ## count: 3 -------------------------------------------------------------------------------- /testData/typeinspection/initAncestor.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | 10 | class B(A): 11 | def __init__(self, a): 12 | super().__init__(a=a) 13 | 14 | 15 | B(a=int(123)) 16 | -------------------------------------------------------------------------------- /testData/ignoreinspection/validatorDataclass.py: -------------------------------------------------------------------------------- 1 | from pydantic import validator 2 | from pydantic.dataclasses import dataclass 3 | 4 | @dataclass 5 | class A: 6 | a: str 7 | 8 | @validator('a') 9 | def validate_a(cls): 10 | pass 11 | -------------------------------------------------------------------------------- /testData/search/field.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str # expected 9 | 10 | A(abc='cde') # expected 11 | B(abc='cde') # expected 12 | ## count: 4 -------------------------------------------------------------------------------- /testData/search/methodLocalVariable.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc = "" 6 | 7 | @classmethod 8 | def do(cls): 9 | abc = "abc" 10 | assert abc # expected 11 | ## count: 2 12 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/parsableTypeDisable.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | b: str 10 | 11 | A(a=str('123'), b=str('123')) 12 | A(a=int(123), b=int(123)) 13 | -------------------------------------------------------------------------------- /testData/completion/parameterAnnotationType.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from typing import Type 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str = 'abc' 9 | efg: str = 'abc' 10 | 11 | 12 | def get_a(a: Type[A]): 13 | a. -------------------------------------------------------------------------------- /testData/ignoreinspection/validatorFullPath.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from pydantic.class_validators import validator 3 | 4 | 5 | class A(BaseModel): 6 | a: str 7 | 8 | @validator('a') 9 | def validate_a(cls): 10 | pass 11 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/root_model.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from .main import BaseModel 4 | 5 | RootModelRootType = typing.TypeVar('RootModelRootType') 6 | 7 | 8 | 9 | class RootModel(BaseModel, typing.Generic[RootModelRootType]): 10 | root: RootModelRootType -------------------------------------------------------------------------------- /testData/typecheckerinspection/acceptableTypeDisable.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | b: str 10 | 11 | A(a=str('123'), b=str('123')) 12 | A(a=int(123), b=int(123)) 13 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentIgnore.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | _abc: str = 'abc' 8 | __cde: str = 'abc' 9 | 10 | 11 | class B(A): 12 | _efg: str = 'abc' 13 | __hij: str = 1 14 | 15 | B() -------------------------------------------------------------------------------- /resources/inspectionDescriptions/PydanticTypeCheckerInspection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This type checker is supporting for Pydantic. It inherits all features from the builtin type checker of PyCharm. Don't use this type checker with builtin type checker same time. 4 | 5 | -------------------------------------------------------------------------------- /testData/completion/parameterAnnotationUnion.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | abc: str 9 | cde: str = 'abc' 10 | efg: str = 'abc' 11 | 12 | 13 | def get_a(a: Union[A, str]): 14 | a. -------------------------------------------------------------------------------- /testData/completion/parameterAnnotationUnionPythonClass.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A: 8 | abc: str 9 | cde: str = 'abc' 10 | efg: str = 'abc' 11 | 12 | 13 | def get_a(a: Union[A, str]): 14 | a. -------------------------------------------------------------------------------- /testData/mock/pydanticv18/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel, BaseConfig, create_model 2 | from .class_validators import validator, root_validator 3 | from .fields import Field, Schema 4 | from .env_settings import BaseSettings 5 | from .networks import * 6 | from .types import * 7 | -------------------------------------------------------------------------------- /testData/search/parentKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | cde: str 7 | 8 | class B(A): 9 | abc: str 10 | cde: str 11 | 12 | A(abc='cde') 13 | B(abc='cde') 14 | # count 1 -------------------------------------------------------------------------------- /testData/completion/conlist.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from pydantic import BaseModel 3 | from pydantic.types import conlist 4 | 5 | class A(BaseModel): 6 | abc: conlist() 7 | cde: conlist(str) 8 | efg: conlist(item_type=str) 9 | hij: conlist(List[str]) 10 | A() -------------------------------------------------------------------------------- /testData/completion/fieldOptional.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union, Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | abc: Optional[str] 9 | cde = 'abc' 10 | efg: str = 'abc' 11 | 12 | class B(A): 13 | hij: str 14 | 15 | A(). -------------------------------------------------------------------------------- /testData/completion/parameterAnnotationTypeKeywordArgument.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from typing import Type 4 | 5 | 6 | class A(BaseModel): 7 | abc: str 8 | cde: str = 'abc' 9 | efg: str = 'abc' 10 | 11 | 12 | def get_a(a: Type[A]): 13 | a() -------------------------------------------------------------------------------- /testData/mock/pydanticv1/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import BaseModel, BaseConfig, create_model, Extra 2 | from .class_validators import validator, root_validator 3 | from .fields import Field, Schema 4 | from .env_settings import BaseSettings 5 | from .networks import * 6 | from .types import * 7 | -------------------------------------------------------------------------------- /testData/typeinspection/ignoreInitArguments.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | def __init__(self, xyz: str): 10 | super().__init__(a=xyz) 11 | 12 | A(xyz=123) 13 | 14 | A(a=123) -------------------------------------------------------------------------------- /testData/ignoreinspection/pythonDecorator.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | def deco(func): 4 | def inner(): 5 | return func() 6 | return inner 7 | 8 | class A(BaseModel): 9 | a: str 10 | 11 | @deco 12 | def validate_a(cls): 13 | pass 14 | -------------------------------------------------------------------------------- /testData/pynesteddecoratorsinspectionsuppressor/modelValidator.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, model_validator 2 | 3 | class Foo(BaseModel): 4 | value: int 5 | 6 | @model_validator(mode="before") 7 | @classmethod 8 | def whatever(cls, data): 9 | return data 10 | -------------------------------------------------------------------------------- /testData/search/grandChildKeywordArgumentNotFound.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | pass 6 | 7 | class B(A): 8 | pass 9 | 10 | class C(B): 11 | pass 12 | 13 | A(abc='cde') 14 | B(abc='cde') 15 | C(abc='cde') 16 | ## count: 0 -------------------------------------------------------------------------------- /testData/search/parameter.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from typing import List, Type 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | def get_a(a: Type[A]): 14 | return a(abc=1) -------------------------------------------------------------------------------- /testData/typecheckerinspection/acceptableTypeInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | A(a=str('123')) 11 | A(a=bytes(123)) 12 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/parsableTypeInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | A(a=str('123')) 11 | A(a=bytes(123)) 12 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldOptionalDefaultValueInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a = int(123) 9 | 10 | 11 | A(a=str('123')) 12 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldOptionalInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: Optional[int] 9 | 10 | 11 | A(a=str('123')) 12 | -------------------------------------------------------------------------------- /testData/search/grandChildKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | pass 9 | 10 | class C(B): 11 | pass 12 | 13 | A(abc='cde') 14 | B(abc='cde') 15 | C(abc='cde') 16 | ## count: 1 -------------------------------------------------------------------------------- /testData/completion/classInitMethod.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class A(BaseModel): 6 | abc: str 7 | 8 | class B: 9 | opq: str 10 | xyz: str = '123' 11 | 12 | class C(A, B): 13 | efg: str 14 | def __init__(self): 15 | return self. 16 | 17 | 18 | -------------------------------------------------------------------------------- /testData/completion/fieldUnion.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | abc: Union[str, int] 9 | cde: Union[str, int] = ... 10 | efg: Union[str, int, None] 11 | 12 | 13 | class B(A): 14 | hij: str 15 | 16 | A(). -------------------------------------------------------------------------------- /testData/search/childrenKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str 6 | 7 | class B(A): 8 | abc: str 9 | 10 | class C(A): 11 | abc: str # expected 12 | 13 | A(abc='cde') 14 | B(abc='cde') 15 | C(abc='cde') 16 | ## count: 1 -------------------------------------------------------------------------------- /testData/search/parentField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | cde: str 7 | 8 | class B(A): 9 | abc: str # expected 10 | cde: str 11 | 12 | A(abc='cde') # expected 13 | B(abc='cde') # expected 14 | ## count: 4 -------------------------------------------------------------------------------- /testData/typecheckerinspection/parsableType.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | 11 | A(a=str('123')) 12 | A(a=int(123)) 13 | -------------------------------------------------------------------------------- /testData/typeinspection/initInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | def __init__(self, a): 10 | super().__init__(a=a) 11 | 12 | 13 | A(a=str('123')) 14 | 15 | -------------------------------------------------------------------------------- /testData/typeinspectionv2/populateByNameAliasEdge.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, ConfigDict, Field 2 | 3 | 4 | class Model(BaseModel): 5 | model_config = ConfigDict(populate_by_name=True) 6 | field_name: str = Field(..., alias="ALIAS_NAME") 7 | 8 | 9 | c = Model(**{"ALIAS_NAME": "test"}) 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldSchema.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Schema 4 | 5 | 6 | class A(BaseModel): 7 | a: int = Schema(int(123)) 8 | b = Schema(123) 9 | c = Schema(default=int(123)) 10 | d: int = Schema(...) 11 | 12 | A(a=int(123), b=int(123), c=int(123), d=int(123)) 13 | -------------------------------------------------------------------------------- /testData/refactor/renameKeywordArgument_after.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Base(BaseModel): 5 | pass 6 | 7 | class A(Base): 8 | cde: str 9 | 10 | class B(A): 11 | cde: int 12 | 13 | class C(Base): 14 | abc: int 15 | 16 | A(cde='abc') 17 | B(cde='abc') 18 | C(abc='abc') 19 | -------------------------------------------------------------------------------- /testData/search/childrenField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str 9 | 10 | class C(A): 11 | abc: str # expected 12 | 13 | A(abc='cde') 14 | B(abc='cde') 15 | C(abc='cde') # expected 16 | ## count: 3 -------------------------------------------------------------------------------- /testData/search/grandChildField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | pass 9 | 10 | class C(B): 11 | abc: str # expected 12 | 13 | A(abc='cde') 14 | B(abc='cde') 15 | C(abc='cde') # expected 16 | ## count: 3 -------------------------------------------------------------------------------- /testData/completion/keywordArgumentInitPosition.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class Z(BaseModel): 6 | def __init__(self, xyz: str): 7 | super().__init__() 8 | class A(Z): 9 | abc: str 10 | cde: str 11 | efg: str 12 | 13 | class B(A): 14 | hij: str 15 | 16 | A() -------------------------------------------------------------------------------- /testData/completion/subscriptionClass.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel 3 | from typing import List, Type 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde = 'abc' 8 | efg: str = 'abc' 9 | 10 | class B(A): 11 | hij: str 12 | 13 | def get_a(a_list: List[Type[A]]): 14 | return a_list[0]() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/noArguments.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A() 15 | -------------------------------------------------------------------------------- /testData/refactor/renameKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Base(BaseModel): 5 | pass 6 | 7 | class A(Base): 8 | abc: str 9 | 10 | class B(A): 11 | abc: int 12 | 13 | class C(Base): 14 | abc: int 15 | 16 | A(abc='abc') 17 | B(abc='abc') 18 | C(abc='abc') 19 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentInitKwargs.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class Z(BaseModel): 6 | def __init__(self, **kwargs): 7 | super().__init__(**kwargs) 8 | class A(Z): 9 | abc: str 10 | cde: str 11 | efg: str 12 | 13 | class B(A): 14 | hij: str 15 | 16 | A() -------------------------------------------------------------------------------- /testData/typecheckerinspection/parsableTypeWeakWarning.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | 11 | A(a=str('123')) 12 | A(a=int(123)) 13 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAllowPopulationByFieldName.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | class A(BaseModel): 6 | abc: str = Field(..., alias='ABC') 7 | cde: str = Field(..., alias='CDE') 8 | 9 | class Config: 10 | allow_population_by_field_name = True 11 | 12 | 13 | A() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/partArguments.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=1, c=2) 15 | -------------------------------------------------------------------------------- /testData/inspection/configDuplicate.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class E(BaseModel, allow_mutation=True): 5 | class Config: 6 | allow_mutation= True 7 | 8 | class F(BaseModel, allow_mutation=True): 9 | pass 10 | 11 | class G(BaseModel): 12 | class Config: 13 | allow_mutation=True 14 | -------------------------------------------------------------------------------- /testData/search/multipleInheritanceField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | pass 9 | 10 | class C(A): 11 | pass 12 | 13 | class D(B, C): 14 | abc: str # expected 15 | 16 | D(abc='cde') # expected 17 | ## count: 3 -------------------------------------------------------------------------------- /testData/typecheckerinspection/acceptableTypeWarning.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | 11 | A(a=str('123')) 12 | A(a=int(123)) 13 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAllowPopulationByFieldNameFalse.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | class A(BaseModel): 6 | abc: str = Field(..., alias='ABC') 7 | cde: str = Field(..., alias='CDE') 8 | 9 | class Config: 10 | allow_population_by_field_name = False 11 | 12 | 13 | A() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/lastCharOnlyRequired.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A() 15 | 16 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentInitArgsKwargs.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class Z(BaseModel): 6 | def __init__(self, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | class A(Z): 9 | abc: str 10 | cde: str 11 | efg: str 12 | 13 | class B(A): 14 | hij: str 15 | 16 | A() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/noArgumentsOnlyRequired.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A() 15 | 16 | -------------------------------------------------------------------------------- /testData/inspectionv2/frozenClassArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Foo(BaseModel, frozen=True): 5 | a: str 6 | 7 | 8 | class Bar(BaseModel): 9 | b: int 10 | 11 | 12 | class ChildFrozen(Bar, frozen=True): 13 | c: str 14 | 15 | 16 | Foo(a="hello") 17 | Bar(b=1) 18 | ChildFrozen(b=2, c="world") 19 | -------------------------------------------------------------------------------- /testData/search/grandChildFieldWithPythonClass.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | pass 6 | 7 | class B(A): 8 | pass 9 | 10 | class D: 11 | pass 12 | 13 | class C(B, D): 14 | abc: str 15 | 16 | 17 | 18 | A(abc='cde') 19 | B(abc='cde') 20 | C(abc='cde') 21 | ## count: 0 -------------------------------------------------------------------------------- /testData/typeinspection/initAncestorInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | 10 | class B(A): 11 | def __init__(self, a): 12 | super().__init__(a=a) 13 | 14 | 15 | B(a=str('123')) 16 | 17 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAllowPopulationByFieldNameChild.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | class A(BaseModel): 6 | abc: str = Field(..., alias='ABC') 7 | cde: str = Field(..., alias='CDE') 8 | 9 | class B(A): 10 | class Config: 11 | allow_population_by_field_name = True 12 | 13 | B() -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAllowPopulationByFieldNameParent.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | class A(BaseModel): 6 | class Config: 7 | allow_population_by_field_name = True 8 | 9 | class B(A): 10 | abc: str = Field(..., alias='ABC') 11 | cde: str = Field(..., alias='CDE') 12 | 13 | B() -------------------------------------------------------------------------------- /testData/completionv2/keywordArgumentPopulateByName.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field, ConfigDict 4 | 5 | class A(BaseModel): 6 | model_config: ConfigDict = ConfigDict( 7 | populate_by_name=True, 8 | ) 9 | abc: str = Field(..., alias='ABC') 10 | cde: str = Field(..., alias='CDE') 11 | 12 | 13 | A() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/lastCharOnlyRequired_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=, b=, e=) 15 | 16 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/nestedOtherObject.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | str(A(a=int(), c=2)) 15 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/nestedPartArguments.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | str(A(a=1, c=2)) 15 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentInitArgsKwargsDisable.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | class Z(BaseModel): 6 | def __init__(self, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | class A(Z): 9 | abc: str 10 | cde: str 11 | efg: str 12 | 13 | class B(A): 14 | hij: str 15 | 16 | A() -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/noArgumentsOnlyRequired_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=, b=, e=) 15 | 16 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/noArguments_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=, b=, c=123, d=123, e=, f=) 15 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/partArgumentsOnlyRequired.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=1, c=2) 15 | 16 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/partArguments_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=1, c=2, b=, d=123, e=, f=) 15 | -------------------------------------------------------------------------------- /testData/search/grandChildKeywordArgumentWithPythonClass.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | pass 6 | 7 | class B(A): 8 | pass 9 | 10 | class D: 11 | pass 12 | 13 | class C(B, D): 14 | pass 15 | 16 | 17 | 18 | A(abc='cde') 19 | B(abc='cde') 20 | C(abc='cde') 21 | ## count: 0 -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/partArgumentsOnlyRequired_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | A(a=1, c=2, b=, e=) 15 | 16 | -------------------------------------------------------------------------------- /testData/refactor/renameGrandChildFieldWithPythonClass.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str 6 | 7 | class B(A): 8 | pass 9 | 10 | class D: 11 | pass 12 | 13 | class C(B, D): 14 | abc: str 15 | 16 | 17 | 18 | A(abc='cde') 19 | B(abc='cde') 20 | C(abc='cde') 21 | ## count: 0 -------------------------------------------------------------------------------- /testData/refactor/renameGrandChildFieldWithPythonClass_after.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | cde: str 6 | 7 | class B(A): 8 | pass 9 | 10 | class D: 11 | pass 12 | 13 | class C(B, D): 14 | cde: str 15 | 16 | 17 | 18 | A(cde='cde') 19 | B(cde='cde') 20 | C(cde='cde') 21 | ## count: 0 -------------------------------------------------------------------------------- /testData/search/multipleInheritanceKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | pass 9 | 10 | class C(A): 11 | pass 12 | 13 | class D: 14 | abc: str 15 | 16 | class F(B, C, D): 17 | pass 18 | 19 | F(abc='cde') 20 | ## count: 1 -------------------------------------------------------------------------------- /testData/search/multipleInheritedField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | abc: str # expected 6 | 7 | class B(A): 8 | abc: str # expected 9 | 10 | class C(A): 11 | abc: str # expected 12 | 13 | class D(B, C): 14 | abc: str # expected 15 | 16 | D(abc='cde') # expected 17 | ## count: 5 -------------------------------------------------------------------------------- /testData/typeinspection/init.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: int 8 | 9 | def __init__(self, a): 10 | super().__init__(a=a) 11 | 12 | 13 | A(a=int(123)) 14 | 15 | class B(BaseModel): 16 | a: int 17 | 18 | def __init__(self, xyz): 19 | super().__init__(a=xyz) 20 | 21 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/nestedPartArguments_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | str(A(a=1, c=2, b=, d=123, e=, f=)) 15 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/nestedOtherObject_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | 13 | 14 | str(A(a=int(), c=2, b=, d=123, e=, f=)) 15 | -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordArgumentsInit.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from pydantic.dataclasses import dataclass 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | def __init__(self, a = '123') -> None: 8 | super(A, self).__init__(a=a) 9 | 10 | A('a') 11 | 12 | @dataclass 13 | class B(): 14 | a: str 15 | 16 | 17 | B('a') 18 | -------------------------------------------------------------------------------- /testData/refactor/renameFieldDataclass.py: -------------------------------------------------------------------------------- 1 | from pydantic.dataclasses import dataclass 2 | 3 | @dataclass 4 | class Base: 5 | pass 6 | 7 | @dataclass 8 | class A(Base): 9 | abc: str 10 | 11 | @dataclass 12 | class B(A): 13 | abc: int 14 | 15 | @dataclass 16 | class C(Base): 17 | abc: str 18 | 19 | A(abc='abc') 20 | B(abc='abc') 21 | C(abc='abc') -------------------------------------------------------------------------------- /testData/refactor/renameFieldDataclass_after.py: -------------------------------------------------------------------------------- 1 | from pydantic.dataclasses import dataclass 2 | 3 | @dataclass 4 | class Base: 5 | pass 6 | 7 | @dataclass 8 | class A(Base): 9 | cde: str 10 | 11 | @dataclass 12 | class B(A): 13 | cde: int 14 | 15 | @dataclass 16 | class C(Base): 17 | abc: str 18 | 19 | A(cde='abc') 20 | B(cde='abc') 21 | C(abc='abc') -------------------------------------------------------------------------------- /testData/refactor/renameField_after.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | class Base(BaseModel): 4 | pass 5 | 6 | class A(Base): 7 | cde: str 8 | xyz: str 9 | 10 | class B(A): 11 | cde: int 12 | xyz: str 13 | 14 | class C(Base): 15 | abc: str 16 | xyz: str 17 | 18 | A(cde='abc', xyz='123') 19 | B(cde='abc', xyz='123') 20 | C(abc='abc', xyz='123') -------------------------------------------------------------------------------- /testData/refactor/renameField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | class Base(BaseModel): 4 | pass 5 | 6 | class A(Base): 7 | abc: str 8 | xyz: str 9 | 10 | class B(A): 11 | abc: int 12 | xyz: str 13 | 14 | class C(Base): 15 | abc: str 16 | xyz: str 17 | 18 | A(abc='abc', xyz='123') 19 | B(abc='abc', xyz='123') 20 | C(abc='abc', xyz='123') -------------------------------------------------------------------------------- /testData/typeinspection/fieldUnionOperatorInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: float | int 9 | 10 | 11 | A(a=bytes(123)) 12 | A(a=str('123')) 13 | -------------------------------------------------------------------------------- /testData/typeinspectionv2/populateByNameAlias.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, ConfigDict, Field 2 | 3 | 4 | class Model(BaseModel): 5 | model_config = ConfigDict(populate_by_name=True) 6 | field_name: str = Field(..., alias="ALIAS_NAME") 7 | 8 | 9 | a = Model(field_name="hello") 10 | b = Model(ALIAS_NAME="world") 11 | 12 | e = Model() 13 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldUnionInvalid.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | a: Union[float, int] 8 | 9 | 10 | A(a=bytes(123)) 11 | A(a=str('123')) 12 | -------------------------------------------------------------------------------- /testData/completionv18/sqlModelClassCompletion.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from sqlmodel import Field, SQLModel 4 | 5 | 6 | class Hero(SQLModel, table=True): 7 | id: Optional[int] = Field(default=None, primary_key=True) 8 | name: str 9 | secret_name: str = Field(default="dummy", primary_key=True) 10 | age: Optional[int] = None 11 | 12 | 13 | Hero. 14 | 15 | -------------------------------------------------------------------------------- /testData/inspection/warnUntypedFieldsDisable.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | a = '123' 6 | 7 | 8 | class B(BaseModel): 9 | b: str = '123' 10 | 11 | 12 | class C: 13 | c = '123' 14 | 15 | 16 | class D: 17 | d 18 | 19 | def e(): 20 | ee = '123' 21 | 22 | f = '123' 23 | 24 | class G(BaseModel): 25 | _g = '123' 26 | __g = '123' -------------------------------------------------------------------------------- /testData/mock/pydanticv2/functional_validators.py: -------------------------------------------------------------------------------- 1 | 2 | def field_validator( 3 | __field: str, 4 | *fields: str, 5 | mode: FieldValidatorModes = 'after', 6 | check_fields: bool | None = None, 7 | ) -> Callable[[Any], Any]: 8 | pass 9 | 10 | 11 | def model_validator( 12 | *, 13 | mode: Literal['wrap', 'before', 'after'], 14 | ) -> Any: 15 | pass -------------------------------------------------------------------------------- /testData/typeinspection/fieldBroken.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Schema 4 | 5 | 6 | class A(BaseModel): 7 | a 8 | b = 9 | c = Schema() 10 | d: 11 | e: = '123' 12 | A(a=int(123), b=str('123'), c=str('456'), d=str('789')) 13 | -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordArgumentsSingleStarArgument.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from pydantic.dataclasses import dataclass 3 | 4 | 5 | class A(BaseModel): 6 | a: str 7 | 8 | 9 | A(*['a']) 10 | 11 | 12 | @dataclass 13 | class B: 14 | a: str 15 | 16 | 17 | B(*['a']) 18 | -------------------------------------------------------------------------------- /testData/typeinspection/allowPopulationByFieldNameAlias.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class Model(BaseModel): 5 | field_name: str = Field(..., alias="ALIAS_NAME") 6 | 7 | class Config: 8 | allow_population_by_field_name = True 9 | 10 | 11 | a = Model(field_name="hello") 12 | b = Model(ALIAS_NAME="world") 13 | 14 | e = Model() 15 | -------------------------------------------------------------------------------- /testData/completionv18/validatorField.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, validator 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str 8 | efg: str 9 | 10 | class B(A): 11 | cde: str 12 | efg: str 13 | hij: str 14 | 15 | class C(B): 16 | efg: str 17 | klm: str 18 | 19 | 20 | @validator('') 21 | def validate(self, values): 22 | return values -------------------------------------------------------------------------------- /testData/completionv2/validatorField.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, field_validator 3 | 4 | 5 | class A(BaseModel): 6 | abc: str 7 | cde: str 8 | efg: str 9 | 10 | class B(A): 11 | cde: str 12 | efg: str 13 | hij: str 14 | 15 | class C(B): 16 | efg: str 17 | klm: str 18 | 19 | 20 | @field_validator('') 21 | def validate(self, values): 22 | return values -------------------------------------------------------------------------------- /testData/inspection/warnUntypedFields.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | a = '123' 6 | 7 | 8 | class B(BaseModel): 9 | b: str = '123' 10 | 11 | 12 | class C: 13 | c = '123' 14 | 15 | class D: 16 | d 17 | 18 | def e(): 19 | ee = '123' 20 | 21 | f = '123' 22 | 23 | class G(BaseModel): 24 | _g = '123' 25 | __g = '123' -------------------------------------------------------------------------------- /testData/mock/pydanticv18/types.py: -------------------------------------------------------------------------------- 1 | 2 | def conlist(item_type, *, min_items = None, max_items = None) Type[List[T]]: 3 | pass 4 | 5 | def constr( 6 | *, 7 | strip_whitespace: bool = False, 8 | to_lower: bool = False, 9 | strict: bool = False, 10 | min_length: int = None, 11 | max_length: int = None, 12 | curtail_length: int = None, 13 | regex: str = None, 14 | ) -> Type[str]: 15 | pass -------------------------------------------------------------------------------- /testData/completion/keywordArgumentFieldAnnotated.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Annotated 3 | from pydantic import BaseModel, Field 4 | 5 | 6 | class A(BaseModel): 7 | abc: Annotated[str, Field(example='example')] 8 | cde: Annotated[str, Field(example='example')] = 'default_value' 9 | efg: Annotated[str, Field(default_factory=lambda: 123)] 10 | a_id: Annotated[str, Field(alias='alias_a_id')] 11 | class B(A): 12 | hij: str 13 | 14 | A() -------------------------------------------------------------------------------- /testData/completion/keywordArgumentAllowPopulationByFieldNameMultipleInheritance.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | class A(BaseModel): 6 | class Config: 7 | allow_population_by_field_name = True 8 | 9 | class B(BaseModel): 10 | class Config: 11 | allow_population_by_field_name = False 12 | 13 | class C(A, B): 14 | abc: str = Field(..., alias='ABC') 15 | cde: str = Field(..., alias='CDE') 16 | 17 | C() -------------------------------------------------------------------------------- /testData/typeinspection/fieldSchemaInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Schema 4 | 5 | 6 | class A(BaseModel): 7 | a: int = Schema(int(123)) 8 | b = Schema(int(123)) 9 | c = Schema(default=int(123)) 10 | 11 | A(a=str('123'), b=str('123'), c=str('123')) 12 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/lastChar.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | g: int = Field(default=123) 13 | h: int = Field(default=...) 14 | i: int = Field(default_factory=lambda: 123) 15 | j: int = Field(default_factory=int) 16 | 17 | 18 | A() 19 | -------------------------------------------------------------------------------- /testData/inspectionv2/extra.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, ConfigDict 2 | 3 | 4 | class A(BaseModel): 5 | model_config = ConfigDict(extra="forbid") 6 | model_233: str 7 | model_id: int 8 | name: str 9 | 10 | 11 | # model_233, model_id are valid fields - no errors 12 | a = A(model_233="bert", model_id=1, name="test") 13 | 14 | # b is an undefined field - error 15 | A(model_233="bert", model_id=1, name="test", b='123') 16 | -------------------------------------------------------------------------------- /testData/typeinspectionv18/baseSetting.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseSettings 2 | 3 | 4 | class AppSettings(BaseSettings): 5 | a: str 6 | b: str 7 | 8 | 9 | AppSettings( 10 | _env_file="dev.env", 11 | env_file_sentinel='abc', 12 | _env_file_encoding='utf-8', 13 | _secrets_dir='xyz' 14 | ) 15 | 16 | AppSettings() 17 | 18 | AppSettings(a=1, b=2) -------------------------------------------------------------------------------- /testData/inspectionv18/validatorField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | 4 | class A(BaseModel): 5 | foo: int 6 | bar: float 7 | 8 | _validate_stuff = validator( 9 | "bar", 10 | allow_reuse=True, 11 | )(do_stuff) 12 | 13 | 14 | class B(BaseModel): 15 | foo: int 16 | bar: float 17 | 18 | _validate_stuff = validator( 19 | "abc", 20 | allow_reuse=True, 21 | )(do_stuff) 22 | -------------------------------------------------------------------------------- /testData/initializer/pyprojecttomldisable/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.pydantic-pycharm-plugin] 2 | # You can select higlith level from "warning", "weak_warning", "disable" 3 | parsable-type-highlight = "disable" 4 | acceptable-type-highlight = "disable" 5 | 6 | [tool.pydantic-pycharm-plugin.parsable-types] 7 | ## datetime.datetime field may parse int 8 | "datetime.datetime" = ["int"] 9 | 10 | [tool.pydantic-pycharm-plugin.acceptable-types] 11 | # str field accepts to parse int and float 12 | str = ["int", "float"] 13 | -------------------------------------------------------------------------------- /testData/mock/stub/typing.py: -------------------------------------------------------------------------------- 1 | class Annotated: ... 2 | class Type: ... 3 | class Union: ... 4 | class Any: ... 5 | class Optional: ... 6 | class List: ... 7 | class Dict: ... 8 | class Tuple: ... 9 | class Generic(object): 10 | @classmethod 11 | def __class_getitem__(cls, *args, **kwargs): ... 12 | @classmethod 13 | def __init_subclass__(cls, *args, **kwargs): ... 14 | def __init__(self, *args, **kwargs): ... 15 | class TypeVar: ... 16 | class ClassVar: ... 17 | class Callable: ... 18 | class Sequence: ... -------------------------------------------------------------------------------- /testData/initializer/mypyini/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = pydantic.mypy 3 | 4 | follow_imports = silent 5 | strict_optional = True 6 | warn_redundant_casts = True 7 | warn_unused_ignores = True 8 | disallow_any_generics = True 9 | check_untyped_defs = True 10 | no_implicit_reexport = True 11 | 12 | # for strict mypy: (this is the tricky one :-)) 13 | disallow_untyped_defs = True 14 | 15 | [pydantic-mypy] 16 | init_forbid_extra = True 17 | init_typed = False 18 | warn_required_dynamic_aliases = True 19 | warn_untyped_fields = True -------------------------------------------------------------------------------- /testData/mock/pydanticv1/types.py: -------------------------------------------------------------------------------- 1 | from typing import Type, List, TypeVar 2 | T = TypeVar('T') 3 | 4 | def conlist(item_type: Type[T], *, min_items = None, max_items = None) -> Type[List[T]]: 5 | pass 6 | 7 | def constr( 8 | *, 9 | strip_whitespace: bool = False, 10 | to_lower: bool = False, 11 | strict: bool = False, 12 | min_length: int = None, 13 | max_length: int = None, 14 | curtail_length: int = None, 15 | regex: str = None, 16 | ) -> Type[str]: 17 | pass -------------------------------------------------------------------------------- /testData/initializer/mypyinibroken/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = pydantic.mypy 3 | 4 | follow_imports = silent 5 | strict_optional = True 6 | warn_redundant_casts = True 7 | warn_unused_ignores = True 8 | disallow_any_generics = True 9 | check_untyped_defs = True 10 | no_implicit_reexport = True 11 | 12 | # for strict mypy: (this is the tricky one :-)) 13 | disallow_untyped_defs = True 14 | 15 | [pydantic-mypy 16 | init_forbid_extra = True 17 | init_typed = False 18 | warn_required_dynamic_aliases = True 19 | warn_untyped_fields = True -------------------------------------------------------------------------------- /testData/initializer/mypyinichange/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | plugins = pydantic.mypy 3 | 4 | follow_imports = silent 5 | strict_optional = True 6 | warn_redundant_casts = True 7 | warn_unused_ignores = True 8 | disallow_any_generics = True 9 | check_untyped_defs = True 10 | no_implicit_reexport = True 11 | 12 | # for strict mypy: (this is the tricky one :-)) 13 | disallow_untyped_defs = True 14 | 15 | [pydantic-mypy] 16 | init_forbid_extra = True 17 | init_typed = False 18 | warn_required_dynamic_aliases = True 19 | warn_untyped_fields = True -------------------------------------------------------------------------------- /testData/typecheckerinspection/fieldImportTyping.py: -------------------------------------------------------------------------------- 1 | 2 | import typing 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: typing.Union[int, str, None] 9 | b: typing.Optional[str] 10 | c: typing.Annotated[str, Field(example='abc')] 11 | d: typing.Any 12 | e: typing.Annotated[typing.Optional[str], Field(example='abc')] 13 | 14 | A(a=int(123), b=None, c='xyz', d='456', e='789') 15 | A(a=str('123'), b='efg', c='xyz', d='456', e=None) 16 | A(a=None, b=str('efg'), c=str('xyz'), d='456') 17 | -------------------------------------------------------------------------------- /testData/completionv18/genericField.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Type, List, Dict, Generic, Optional 2 | from pydantic.generics import GenericModel 3 | 4 | 5 | AT = TypeVar('AT') 6 | BT = TypeVar('BT') 7 | CT = TypeVar('CT') 8 | DT = TypeVar('DT') 9 | ET = TypeVar('ET') 10 | 11 | 12 | class A(GenericModel, Generic[AT, BT, CT, DT]): 13 | a: Type[AT] 14 | b: List[BT] 15 | c: Dict[CT, DT] 16 | 17 | class B(A[int, BT, CT, DT], Generic[BT, CT, DT, ET]): 18 | hij: Optional[ET] 19 | 20 | 21 | B[str, float, bytes, bool](). -------------------------------------------------------------------------------- /testData/initializer/pyprojecttomlchange/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.pydantic-pycharm-plugin] 2 | # You can select higlith level from "warning", "weak_warning", "disable" 3 | parsable-type-highlight = "weak_warning" 4 | acceptable-type-highlight = "invalid" 5 | 6 | [tool.pydantic-pycharm-plugin.parsable-types] 7 | ## datetime.datetime field may parse int 8 | "datetime.datetime" = ["int"] 9 | "pydantic.HttpUrl" = ["str"] 10 | [tool.pydantic-pycharm-plugin.acceptable-types] 11 | # str field accepts to parse int and float 12 | str = ["int", "float"] 13 | -------------------------------------------------------------------------------- /testData/initializer/pyprojecttomldefault/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.pydantic-pycharm-plugin] 2 | # You can select higlith level from "warning", "weak_warning", "disable" 3 | parsable-type-highlight = "warning" 4 | acceptable-type-highlight = "weak_warning" 5 | 6 | [tool.pydantic-pycharm-plugin.parsable-types] 7 | ## datetime.datetime field may parse int 8 | "datetime.datetime" = ["int"] 9 | "pydantic.HttpUrl" = ["str"] 10 | [tool.pydantic-pycharm-plugin.acceptable-types] 11 | # str field accepts to parse int and float 12 | str = ["int", "float"] 13 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/lastChar_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, Field 3 | 4 | 5 | class A(BaseModel): 6 | a: int 7 | b: int = ... 8 | c: int = 123 9 | d: int = Field(123) 10 | e: int = Field(...) 11 | f: Optional[int] 12 | g: int = Field(default=123) 13 | h: int = Field(default=...) 14 | i: int = Field(default_factory=lambda: 123) 15 | j: int = Field(default_factory=int) 16 | 17 | 18 | A(a=, b=, c=123, d=123, e=, f=, g=123, h=, i=lambda: 123, j=int) 19 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/env_settings.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Any, Optional, Union 3 | 4 | from .main import BaseModel 5 | 6 | env_file_sentinel = str(object()) 7 | 8 | class BaseSettings(BaseModel): 9 | def __init__( 10 | __pydantic_self__, 11 | _env_file: Union[Path, str, None] = env_file_sentinel, 12 | _env_file_encoding: Optional[str] = None, 13 | _secrets_dir: Union[Path, str, None] = None, 14 | **values: Any, 15 | ) -> None: 16 | pass 17 | -------------------------------------------------------------------------------- /testData/completionv18/genericKeywordArgument.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Type, List, Dict, Generic, Optional 2 | from pydantic.generics import GenericModel 3 | 4 | 5 | AT = TypeVar('AT') 6 | BT = TypeVar('BT') 7 | CT = TypeVar('CT') 8 | DT = TypeVar('DT') 9 | ET = TypeVar('ET') 10 | 11 | 12 | class A(GenericModel, Generic[AT, BT, CT, DT]): 13 | a: Type[AT] 14 | b: List[BT] 15 | c: Dict[CT, DT] 16 | 17 | class B(A[int, BT, CT, DT], Generic[BT, CT, DT, ET]): 18 | hij: Optional[ET] 19 | 20 | 21 | B[str, float, bytes, bool]() -------------------------------------------------------------------------------- /testData/typecheckerinspection/field.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from typing import * 4 | 5 | from pydantic import BaseModel 6 | 7 | 8 | class A(BaseModel): 9 | a: int 10 | b: Any 11 | c: Optional[int] 12 | d: Union[str, int, None] 13 | 14 | 15 | A(a=int(123)) 16 | A(a=int(123), b=456, c=789, d=345) 17 | A(a='123', b=456, c='789', d=b'234') -------------------------------------------------------------------------------- /testData/inspection/kwargConfig.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class B(BaseModel, allow_mutation=False): 5 | abc: str = '123' 6 | B.abc = '456' 7 | 8 | class C(BaseModel, allow_mutation=True): 9 | abc: str = '123' 10 | C.abc = '456' 11 | C().abc = '456' 12 | 13 | class D(BaseModel, allow_mutation=False): 14 | pass 15 | D.abc = '456' 16 | 17 | allow_mutation = True 18 | class E(BaseModel, allow_mutation=allow_mutation): 19 | pass 20 | E.abc = '456' 21 | E().abc = '456' 22 | 23 | 24 | class F(D, allow_mutation=False): 25 | pass 26 | F.abc = '456' 27 | -------------------------------------------------------------------------------- /testData/completion/fieldAnnotated.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Annotated 3 | from pydantic import BaseModel, Field 4 | 5 | class Info: 6 | pass 7 | class A(BaseModel): 8 | abc: Annotated[str, Field(example='example')] 9 | cde: Annotated[str, Field(example='example')] = 'default_value' 10 | efg: Annotated[str, Field(default_factory=lambda: 123)] 11 | a_id: Annotated[str, Field(alias='alias_a_id')] 12 | klm: Annotated[str, Info(), Field(default_factory=lambda: 456)] 13 | nop: Annotated[str, Field(default_factory=lambda: 789), Info()] 14 | class B(A): 15 | hij: str 16 | 17 | A(). -------------------------------------------------------------------------------- /testData/typeinspection/fieldField.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | NUMBER = 123 6 | 7 | class A(BaseModel): 8 | a: int = Field(int(123)) 9 | b = Field(123) 10 | c = Field(default=int(123)) 11 | d: int = Field(...) 12 | e: int = Field(NUMBER) 13 | f: int = Field(default=NUMBER) 14 | g = Field(NUMBER) 15 | h: int = Field(NUMBER) 16 | i: int = Field(default=NUMBER) 17 | j = Field(NUMBER) 18 | k: Optional[int] = Field() 19 | 20 | A(a=int(123), b=int(123), c=int(123), d=int(123), e=int(123), f=int(123), g=int(123)) 21 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/acceptableType.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: str 9 | 10 | 11 | A(a=str('123')) 12 | A(a=int(123)) 13 | 14 | def get_unknown_type_value(): 15 | raise Exception() 16 | 17 | A(a=get_unknown_type_value()) 18 | A(a=None) 19 | 20 | class B: 21 | pass 22 | 23 | A(a=B()) 24 | -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticPyNestedDecoratorsInspectionSuppressorTest.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import com.jetbrains.python.inspections.PyNestedDecoratorsInspection 5 | import kotlin.reflect.KClass 6 | 7 | 8 | open class PydanticPyNestedDecoratorsInspectionSuppressorTest : PydanticInspectionBase(version = "v2") { 9 | 10 | @Suppress("UNCHECKED_CAST") 11 | override val inspectionClass: KClass = PyNestedDecoratorsInspection::class as KClass 12 | 13 | fun testModelValidator() { 14 | doTest() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testData/initializer/pyprojecttoml/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.pydantic-pycharm-plugin] 2 | # You can select higlith level from "warning", "weak_warning", "disable" 3 | parsable-type-highlight = "weak_warning" 4 | acceptable-type-highlight = "warning" 5 | 6 | ignore-init-method-arguments = true 7 | ignore-init-method-keyword-arguments = false 8 | 9 | 10 | [tool.pydantic-pycharm-plugin.parsable-types] 11 | ## datetime.datetime field may parse int 12 | "datetime.datetime" = ["int"] 13 | "pydantic.HttpUrl" = ["str"] 14 | [tool.pydantic-pycharm-plugin.acceptable-types] 15 | # str field accepts to parse int and float 16 | str = ["int", "float"] 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticDynamicModelClassType.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.psi.types.PyCallableType 4 | import com.jetbrains.python.psi.types.PyCallableTypeImpl 5 | import com.jetbrains.python.psi.types.PyClassTypeImpl 6 | 7 | class PydanticDynamicModelClassType(private val source: PydanticDynamicModel, isDefinition: Boolean) : 8 | PyClassTypeImpl(source, isDefinition) { 9 | 10 | val pyCallableType: PyCallableType 11 | get() = PyCallableTypeImpl( 12 | source.attributes.values.map { attribute -> attribute.pyCallableParameter }, 13 | this.toInstance() 14 | ) 15 | } -------------------------------------------------------------------------------- /testData/completion/fieldIgnore.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import ClassVar 3 | from pydantic import BaseModel 4 | 5 | class Descriptor: 6 | def __get__(self, instance, owner): 7 | return owner 8 | 9 | class A(BaseModel): 10 | _abc: str = 'abc' 11 | __cde: str = 'abc' 12 | efg: ClassVar[str] = 'abc' 13 | class Config: 14 | keep_untouched = (Descriptor,) 15 | 16 | descriptor1 = Descriptor() 17 | 18 | class B(A): 19 | _efg: str = 'abc' 20 | __hij: str = 'abc' 21 | klm: ClassVar[str] = 'abc' 22 | class Config: 23 | keep_untouched = (Descriptor,) 24 | 25 | descriptor2 = Descriptor() 26 | A(). -------------------------------------------------------------------------------- /testData/typecheckerinspection/parsableTypeCollection.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union, List 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: List[str] 9 | b: List[List[str]] 10 | 11 | a_int: List[int] = [int('123')] 12 | a_str: List[str] = [str('123')] 13 | b_int: List[List[int]] = [[int('123')]] 14 | b_str: List[List[str]] = [[str('123')]] 15 | A(a=a_str, b=b_str) 16 | A(a=a_int, b=b_int) 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | # Check for updates to GitHub Actions every weekday 7 | interval: "daily" 8 | open-pull-requests-limit: 10 9 | 10 | - package-ecosystem: gradle 11 | directory: "/" 12 | schedule: 13 | interval: daily 14 | time: "10:00" 15 | timezone: Asia/Tokyo 16 | open-pull-requests-limit: 10 17 | 18 | - package-ecosystem: pip 19 | directory: "/" 20 | schedule: 21 | interval: daily 22 | time: "10:00" 23 | timezone: Asia/Tokyo 24 | open-pull-requests-limit: 10 25 | -------------------------------------------------------------------------------- /testData/completion/fieldField.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Field 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Field(...) 9 | cde = Field('abc') 10 | efg = Field(default='abc') 11 | hij = Field(default=...) 12 | a_id: str = Field(..., alias='alias_a_id') 13 | b_id: str = Field(..., alias=b_id) 14 | c_id: str = Field(..., alias=get_alias()) 15 | d_id: str = Field(..., alias=) 16 | e_id: str = Field(..., alias=broken) 17 | f_id: str = Field(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A(). -------------------------------------------------------------------------------- /testData/completion/fieldSchemaField.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Field 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Field(...) 9 | cde = Field('abc') 10 | efg = Field(default='abc') 11 | hij = Field(default=...) 12 | a_id: str = Field(..., alias='alias_a_id') 13 | b_id: str = Field(..., alias=b_id) 14 | c_id: str = Field(..., alias=get_alias()) 15 | d_id: str = Field(..., alias=) 16 | e_id: str = Field(..., alias=broken) 17 | f_id: str = Field(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A(). -------------------------------------------------------------------------------- /testData/completion/fieldSchema.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Schema 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Schema(...) 9 | cde = Schema('abc') 10 | efg = Schema(default='abc') 11 | hij = Schema(default=...) 12 | a_id: str = Schema(..., alias='alias_a_id') 13 | b_id: str = Schema(..., alias=b_id) 14 | c_id: str = Schema(..., alias=get_alias()) 15 | d_id: str = Schema(..., alias=) 16 | e_id: str = Schema(..., alias=broken) 17 | f_id: str = Schema(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A(). -------------------------------------------------------------------------------- /testData/completionv0/fieldSchema.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Schema 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Schema(...) 9 | cde = Schema('abc') 10 | efg = Schema(default='abc') 11 | hij = Schema(default=...) 12 | a_id: str = Schema(..., alias='alias_a_id') 13 | b_id: str = Schema(..., alias=b_id) 14 | c_id: str = Schema(..., alias=get_alias()) 15 | d_id: str = Schema(..., alias=) 16 | e_id: str = Schema(..., alias=broken) 17 | f_id: str = Schema(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A(). -------------------------------------------------------------------------------- /testData/completion/keywordArgumentSchemaField.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Field 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id: str = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Field(...) 9 | cde = Field('abc') 10 | efg = Field(default='abc') 11 | hij = Field(default=...) 12 | a_id: str = Field(..., alias='alias_a_id') 13 | b_id: str = Field(..., alias=b_id) 14 | c_id: str = Field(..., alias=get_alias()) 15 | d_id: str = Field(..., alias=) 16 | e_id: str = Field(..., alias=broken) 17 | f_id: str = Field(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A() -------------------------------------------------------------------------------- /testData/mock/pydanticv1/fields.py: -------------------------------------------------------------------------------- 1 | def Field( 2 | default, 3 | *, 4 | alias: str = None, 5 | title: str = None, 6 | description: str = None, 7 | const: bool = None, 8 | gt: float = None, 9 | ge: float = None, 10 | lt: float = None, 11 | le: float = None, 12 | multiple_of: float = None, 13 | min_items: int = None, 14 | max_items: int = None, 15 | min_length: int = None, 16 | max_length: int = None, 17 | regex: str = None, 18 | **extra, 19 | ): 20 | 21 | pass 22 | 23 | 24 | def Schema(*args, **kwargs): 25 | return Field(*args, **kwargs) 26 | -------------------------------------------------------------------------------- /testData/completion/keywordArgumentSchema.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Schema 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id: str = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Schema(...) 9 | cde = Schema('abc') 10 | efg = Schema(default='abc') 11 | hij = Schema(default=...) 12 | a_id: str = Schema(..., alias='alias_a_id') 13 | b_id: str = Schema(..., alias=b_id) 14 | c_id: str = Schema(..., alias=get_alias()) 15 | d_id: str = Schema(..., alias=) 16 | e_id: str = Schema(..., alias=broken) 17 | f_id: str = Schema(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A() -------------------------------------------------------------------------------- /testData/completionv0/keywordArgumentSchema.py: -------------------------------------------------------------------------------- 1 | 2 | from pydantic import BaseModel, Schema 3 | 4 | def get_alias(): 5 | return 'alias_c_id' 6 | b_id: str = 'alias_b_id' 7 | class A(BaseModel): 8 | abc: str = Schema(...) 9 | cde = Schema('abc') 10 | efg = Schema(default='abc') 11 | hij = Schema(default=...) 12 | a_id: str = Schema(..., alias='alias_a_id') 13 | b_id: str = Schema(..., alias=b_id) 14 | c_id: str = Schema(..., alias=get_alias()) 15 | d_id: str = Schema(..., alias=) 16 | e_id: str = Schema(..., alias=broken) 17 | f_id: str = Schema(..., alias=123) 18 | g_id: str = get_alias() 19 | class B(A): 20 | hij: str 21 | 22 | A() -------------------------------------------------------------------------------- /testData/mock/pydanticv2/v1/fields.py: -------------------------------------------------------------------------------- 1 | def Field( 2 | default, 3 | *, 4 | alias: str = None, 5 | title: str = None, 6 | description: str = None, 7 | const: bool = None, 8 | gt: float = None, 9 | ge: float = None, 10 | lt: float = None, 11 | le: float = None, 12 | multiple_of: float = None, 13 | min_items: int = None, 14 | max_items: int = None, 15 | min_length: int = None, 16 | max_length: int = None, 17 | regex: str = None, 18 | **extra, 19 | ): 20 | 21 | pass 22 | 23 | 24 | def Schema(*args, **kwargs): 25 | return Field(*args, **kwargs) 26 | -------------------------------------------------------------------------------- /testData/inspection/acceptsOnlyKeywordArguments.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from pydantic.dataclasses import dataclass 3 | 4 | class A(BaseModel): 5 | a: str 6 | 7 | 8 | A('a') 9 | 10 | @dataclass 11 | class B(): 12 | a: str 13 | 14 | 15 | B('a') 16 | 17 | class C(BaseModel): 18 | a: str 19 | def __call__(self, *args, **kwargs): 20 | pass 21 | 22 | c = C(a='abc') 23 | 24 | c('a') 25 | 26 | @dataclass 27 | class D(): 28 | a: str 29 | b: str 30 | 31 | 32 | D('a') 33 | 34 | 35 | class E(BaseModel): 36 | pass 37 | 38 | E() 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /testData/mock/pydanticv0/schema.py: -------------------------------------------------------------------------------- 1 | class Schema: 2 | def __init__( 3 | self, 4 | default, 5 | *, 6 | alias: str = None, 7 | title: str = None, 8 | description: str = None, 9 | const: bool = None, 10 | gt: float = None, 11 | ge: float = None, 12 | lt: float = None, 13 | le: float = None, 14 | multiple_of: float = None, 15 | min_items: int = None, 16 | max_items: int = None, 17 | min_length: int = None, 18 | max_length: int = None, 19 | regex: str = None, 20 | **extra, 21 | ) -> None: 22 | pass 23 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/fields.py: -------------------------------------------------------------------------------- 1 | def Field( 2 | default, 3 | *, 4 | alias: str = None, 5 | title: str = None, 6 | description: str = None, 7 | const: bool = None, 8 | gt: float = None, 9 | ge: float = None, 10 | lt: float = None, 11 | le: float = None, 12 | multiple_of: float = None, 13 | min_items: int = None, 14 | max_items: int = None, 15 | min_length: int = None, 16 | max_length: int = None, 17 | regex: str = None, 18 | default_factory = None, 19 | **extra, 20 | ): 21 | 22 | pass 23 | 24 | 25 | def Schema(*args, **kwargs): 26 | return Field(*args, **kwargs) 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | .idea/workspace.xml 26 | .idea/modules.xml 27 | .idea/compiler.xml 28 | .idea/misc.xml 29 | .idea/gradle.xml 30 | .idea/shelf/ 31 | .idea/libraries/ 32 | .idea/dictionaries 33 | .idea/.name 34 | *.iml 35 | 36 | /build/ 37 | /jps-plugin/build/ 38 | .gradle 39 | /out/ 40 | /pydantic-pycahrm-plugin/out/ 41 | /venv/ 42 | /site 43 | /docs/changelog.md -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticInspectionBase.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import kotlin.reflect.KClass 5 | 6 | 7 | abstract class PydanticInspectionBase(version: String = "v1") : PydanticTestCase(version) { 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | protected open val inspectionClass: KClass = PydanticInspection::class as KClass 11 | 12 | private fun configureInspection() { 13 | myFixture!!.enableInspections(inspectionClass.java) 14 | myFixture!!.checkHighlighting(true, false, true) 15 | 16 | } 17 | 18 | protected fun doTest() { 19 | configureByFile() 20 | configureInspection() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticTypeInspectionV2Test.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import com.jetbrains.python.inspections.PyTypeCheckerInspection 5 | import kotlin.reflect.KClass 6 | 7 | 8 | open class PydanticTypeInspectionV2Test : PydanticInspectionBase("v2") { 9 | 10 | @Suppress("UNCHECKED_CAST") 11 | override val inspectionClass: KClass = PyTypeCheckerInspection::class as KClass 12 | 13 | fun testPopulateByNameAlias() { 14 | doTest() 15 | } 16 | 17 | fun testPopulateByNameAliasEdge() { 18 | doTest() 19 | } 20 | 21 | fun testBaseSettingPydanticSettings() { 22 | doTest() 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticValidatorFieldReference.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.psi.* 4 | import com.intellij.psi.util.PsiTreeUtil 5 | import com.jetbrains.python.psi.* 6 | import com.jetbrains.python.psi.types.TypeEvalContext 7 | 8 | class PydanticValidatorFieldReference(element: PyStringLiteralExpression) : 9 | PsiReferenceBase(element) { 10 | 11 | override fun resolve(): PsiElement? { 12 | val pyClass = PsiTreeUtil.getParentOfType(element, PyClass::class.java) ?: return null 13 | val typeEvalContext = TypeEvalContext.userInitiated(element.project, element.containingFile) 14 | return pyClass.findClassAttribute(element.stringValue, true, typeEvalContext) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/dataclass.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from dataclasses import field 3 | from pydantic import BaseModel, Field 4 | from pydantic.dataclasses import dataclass 5 | 6 | @dataclass 7 | class A: 8 | a: int 9 | b: int = ... 10 | c: int = 123 11 | d: int = Field(123) 12 | e: int = Field(...) 13 | f: Optional[int] 14 | g: int = Field(default=123) 15 | h: int = Field(default=...) 16 | i: int = Field(default_factory=lambda: 123) 17 | j: int = Field(default_factory=int) 18 | k: int = field(123) 19 | l: int = field(...) 20 | m: int = field(default=123) 21 | n: int = field(default=...) 22 | o: int = field(default_factory=lambda: 123) 23 | p: int = field(default_factory=int) 24 | 25 | A() 26 | -------------------------------------------------------------------------------- /docs/ignore-init-keyword-arguments.md: -------------------------------------------------------------------------------- 1 | # Ignore `__init__` method arguments 2 | 3 | 4 | !!! info 5 | **This feature is in version 0.4.8 or later** 6 | 7 | You can write `__init__` method on a model for adding some logic. 8 | 9 | However, default arguments on `__init__` method will be overridden, And you will lose autocompletion for `__init__` methods by the plugin. 10 | 11 | ![options_init](init_arguments.png) 12 | 13 | `ignore-init-method-arguments` option resolves this problem. 14 | The option ignore arguments on `__init__` method. 15 | 16 | ![options_ignore_init](ignore_init_arguments.png) 17 | 18 | 19 | The option has to be defined in pyproject.toml 20 | 21 | ```toml 22 | [tool.pydantic-pycharm-plugin] 23 | ignore-init-method-keyword-arguments = false 24 | 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /testData/typeinspection/fieldFieldInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | NUMBER = 123 6 | 7 | class A(BaseModel): 8 | a: int = Field(int(123)) 9 | b = Field(int(123)) 10 | c = Field(default=int(123)) 11 | e: int = Field(NUMBER) 12 | f: int = Field(default=NUMBER) 13 | g = Field(NUMBER) 14 | 15 | A(a=str('123'), b=str('123'), c=str('123'), e=str('123'), f=str('123'), g=str('123')) 16 | -------------------------------------------------------------------------------- /testData/inspection/customRoot.py: -------------------------------------------------------------------------------- 1 | from typing import ClassVar 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class A(BaseModel): 7 | __root__ = 'xyz' 8 | 9 | 10 | class B(BaseModel): 11 | a = 'xyz' 12 | 13 | 14 | class C(BaseModel): 15 | __root__ = 'xyz' 16 | b = 'xyz' 17 | 18 | 19 | class D(BaseModel): 20 | __root__ = 'xyz' 21 | _c = 'xyz' 22 | __c = 'xyz' 23 | 24 | class E: 25 | __root__ = 'xyz' 26 | e = 'xyz' 27 | 28 | def f(): 29 | __root__ = 'xyz' 30 | g = 'xyz' 31 | 32 | class G(BaseModel): 33 | ATTRIBUTE_NAME: ClassVar[str] = "testing" 34 | __root__ = 'xyz' 35 | 36 | class H(BaseModel): 37 | __root__ = 'xyz' 38 | b: str 39 | 40 | -------------------------------------------------------------------------------- /testData/inspection/extra.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Extra 2 | 3 | class A(BaseModel): 4 | class Config: 5 | extra = Extra.ignore 6 | 7 | A(a='123') 8 | 9 | 10 | class B(BaseModel): 11 | a: str 12 | class Config: 13 | extra = Extra.forbid 14 | 15 | B(a='abc', b='123') 16 | params = {'a': 'abc', 'b': '123'} 17 | B(**params) 18 | 19 | 20 | class C(BaseModel): 21 | id: int 22 | 23 | 24 | class D(C): 25 | data: List[int] 26 | 27 | class Config: 28 | extra = Extra.forbid 29 | 30 | 31 | d = D(id=1, data=[1, 2, 3]) 32 | 33 | class E(BaseModel): 34 | a: str 35 | class Config: 36 | extra = Extra.forbid 37 | 38 | def __call__(self, *args, **kwargs): 39 | pass 40 | 41 | e = E(a='abc') 42 | 43 | e(a='efg', b='xyz') 44 | -------------------------------------------------------------------------------- /testData/inspectionv18/kwargConfig.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class B(BaseModel, allow_mutation=False): 5 | abc: str = '123' 6 | B.abc = '456' 7 | B().abc = '456' 8 | 9 | class C(BaseModel, allow_mutation=True): 10 | abc: str = '123' 11 | C.abc = '456' 12 | C().abc = '456' 13 | 14 | class D(BaseModel, allow_mutation=False): 15 | pass 16 | D.abc = '456' 17 | D().abc = '456' 18 | 19 | allow_mutation = True 20 | class E(BaseModel, allow_mutation=allow_mutation): 21 | pass 22 | E.abc = '456' 23 | E().abc = '456' 24 | 25 | 26 | class F(D, allow_mutation=False): 27 | pass 28 | F.abc = '456' 29 | F().abc = '456' 30 | -------------------------------------------------------------------------------- /testData/typeinspectionv18/sqlModel.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | from sqlmodel import Field, SQLModel 4 | 5 | 6 | class Hero(SQLModel, table=True): 7 | id: Optional[int] = Field(default=None, primary_key=True) 8 | name: str 9 | secret_name = Field(default="dummy", primary_key=True) 10 | age: Optional[int] = None 11 | 12 | hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") 13 | hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") 14 | hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) 15 | 16 | hero_4 = Hero(secret_name="test") 17 | 18 | hero_5 = Hero(name=123, secret_name=456, age="abc") -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | # Development 2 | ## Building the plugin 3 | You can build and run the plugin either via the command line or through IntelliJ IDEA: 4 | 5 | ### Shell on Linux, macOS and PowerShell 6 | ```bash 7 | ./gradlew buildPlugin 8 | ``` 9 | 10 | ### Command Prompt on Windows 11 | ```cmd 12 | gradlew buildPlugin 13 | ``` 14 | 15 | ### JetBrains IDE on any platform 16 | 17 | [Official documentation](https://plugins.jetbrains.com/docs/intellij/getting-started.html]) 18 | 19 | ## Running the IDE with the built plugin 20 | ```bash 21 | ./gradlew runIde 22 | ``` 23 | 24 | 25 | ## License For testSrc/com/jetbrains 26 | These files are copied to `testSrc/com/jetbrains` from [IntelliJ IDEA Community Edition](https://github.com/JetBrains/intellij-community) 27 | The files are licensed under the Apache License, Version 2.0. 28 | http://www.apache.org/licenses/LICENSE-2.0 29 | -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticInspectionV18Test.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import kotlin.reflect.KClass 5 | 6 | 7 | open class PydanticInspectionV18Test : PydanticInspectionBase(version = "v18") { 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | override val inspectionClass: KClass = PydanticInspection::class as KClass 11 | 12 | fun testConfigDuplicate() { 13 | doTest() 14 | } 15 | 16 | fun testKwargConfig() { 17 | doTest() 18 | } 19 | 20 | fun testReadOnlyProperty() { 21 | doTest() 22 | } 23 | 24 | fun testReadOnlyPropertyFrozen() { 25 | doTest() 26 | } 27 | 28 | fun testDefaultFactory() { 29 | doTest() 30 | } 31 | 32 | fun testValidatorField() { 33 | doTest() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /testData/insertargumentsquickfix/dataclass_after.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from dataclasses import field 3 | from pydantic import BaseModel, Field 4 | from pydantic.dataclasses import dataclass 5 | 6 | @dataclass 7 | class A: 8 | a: int 9 | b: int = ... 10 | c: int = 123 11 | d: int = Field(123) 12 | e: int = Field(...) 13 | f: Optional[int] 14 | g: int = Field(default=123) 15 | h: int = Field(default=...) 16 | i: int = Field(default_factory=lambda: 123) 17 | j: int = Field(default_factory=int) 18 | k: int = field(123) 19 | l: int = field(...) 20 | m: int = field(default=123) 21 | n: int = field(default=...) 22 | o: int = field(default_factory=lambda: 123) 23 | p: int = field(default_factory=int) 24 | 25 | 26 | A(a=, b=, c=123, d=123, e=, f=, g=123, h=, i=lambda: 123, j=int, k=123, l=, m=123, n=, o=lambda: 123, p=int) 27 | -------------------------------------------------------------------------------- /testData/inspectionv2/validators.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator, root_validator 2 | 3 | def check(func): 4 | def inner(): 5 | func() 6 | return inner 7 | 8 | class A(BaseModel): 9 | a: str 10 | 11 | 12 | @validator('a') 13 | def validate_a(cls): 14 | pass 15 | 16 | @root_validator() 17 | def validate_root(cls): 18 | pass 19 | 20 | 21 | def dummy(self): 22 | pass 23 | 24 | @check 25 | def task(self): 26 | pass -------------------------------------------------------------------------------- /resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /testSrc/com/jetbrains/python/PythonTestUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2013 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.jetbrains.python 17 | 18 | /** 19 | * @author yole 20 | */ 21 | object PythonTestUtil { 22 | val testDataPath: String 23 | get() = System.getProperty("user.dir") + "/testData" 24 | } -------------------------------------------------------------------------------- /testData/completion/dataclassKeywordArgument.py: -------------------------------------------------------------------------------- 1 | 2 | from dataclasses import field, MISSING 3 | 4 | from pydantic.dataclasses import dataclass, Field 5 | 6 | 7 | def dummy(): 8 | return '123' 9 | 10 | @dataclass 11 | class A: 12 | abc: str 13 | cde: str = field(default=...) 14 | efg: str = field(default='xyz') 15 | hij: str = field(default_factory=lambda :'asd') 16 | klm: str = field(default='qwe', init=True) 17 | nop: str = field(default='rty', init=False) 18 | qrs: str = 'fgh' 19 | tuw: str = field(default=MISSING) 20 | xyz: str = field(default_factory=MISSING) 21 | cda: str = field(default=MISSING, default_factory=MISSING) 22 | edc: str = dummy() 23 | gef: str = field(default=unresolved) 24 | jih: str = field(..., title="empty", ) 25 | mlk: str = field(..., title="empty", ) 26 | 27 | @dataclass 28 | class B(A): 29 | child: str 30 | 31 | A() -------------------------------------------------------------------------------- /testData/inspectionv18/configDuplicate.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class E(BaseModel, allow_mutation=True): 7 | class Config: 8 | allow_mutation= True 9 | 10 | class F(BaseModel, allow_mutation=True): 11 | pass 12 | 13 | class G(BaseModel): 14 | class Config: 15 | allow_mutation=True 16 | 17 | class H(BaseModel, metaclass=abc.ABCMeta, allow_mutation=True): 18 | class Config: 19 | allow_mutation= True 20 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Pydantic PyCharm Plugin 2 | site_description: A JetBrains PyCharm plugin for pydantic. 3 | 4 | theme: 5 | name: 'material' 6 | palette: 7 | primary: 'light blue' 8 | accent: 'light blue' 9 | analytics: 10 | gtag: 275257853 11 | markdown_extensions: 12 | - codehilite 13 | - admonition 14 | - toc: 15 | permalink: 🔗 16 | 17 | repo_name: koxudaxi/pydantic-pycharm-plugin 18 | repo_url: https://github.com/koxudaxi/pydantic-pycharm-plugin 19 | site_url: https://koxudaxi.github.io/pydantic-pycharm-plugin 20 | 21 | nav: 22 | - Overview: index.md 23 | - Install: install.md 24 | - Usage: 25 | - Type checker for pydantic: type-checker-for-pydantic.md 26 | - Mypy compatible: mypy-compatible.md 27 | - Ignore __init__ arguments: ignore-init-arguments.md 28 | - Development: development.md 29 | - Changelog: CHANGELOG.md 30 | 31 | plugins: 32 | - search -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | Also, gif movies are recommended. 26 | 27 | **Environments (please complete the following information):** 28 | - IDE: [e.g. PyCharm Community 2022.1 ] 29 | - OS: [e.g. macOS 12.2.0 ] 30 | - Pydantic Version [e.g. 1.9.0 ] 31 | - Plugin version [e.g. 0.3.11 ] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/_internal/_config/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | config_defaults = ConfigDict( 3 | title=None, 4 | str_to_lower=False, 5 | str_to_upper=False, 6 | str_strip_whitespace=False, 7 | str_min_length=0, 8 | str_max_length=None, 9 | # let the model / dataclass decide how to handle it 10 | extra=None, 11 | frozen=False, 12 | populate_by_name=False, 13 | use_enum_values=False, 14 | validate_assignment=False, 15 | arbitrary_types_allowed=False, 16 | from_attributes=False, 17 | loc_by_alias=True, 18 | alias_generator=None, 19 | ignored_types=(), 20 | allow_inf_nan=True, 21 | json_schema_extra=None, 22 | strict=False, 23 | revalidate_instances='never', 24 | ser_json_timedelta='iso8601', 25 | ser_json_bytes='utf8', 26 | validate_default=False, 27 | validate_return=False, 28 | protected_namespaces=('model_',), 29 | hide_input_in_errors=False, 30 | ) 31 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Setup Python 15 | uses: actions/setup-python@v5.4.0 16 | with: 17 | python-version: '3.11' 18 | architecture: 'x64' 19 | 20 | - uses: actions/cache@v5 21 | with: 22 | path: ~/.cache/pip 23 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} 24 | - name: Install dependencies 25 | run: | 26 | pip install -r requirements.txt 27 | - run: | 28 | cp CHANGELOG.md docs 29 | mkdocs build --verbose --clean --strict 30 | 31 | - name: Deploy 32 | uses: peaceiris/actions-gh-pages@v4 33 | with: 34 | github_token: ${{ secrets.GITHUB_TOKEN }} 35 | publish_dir: ./site 36 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # libraries 3 | annotations = "26.0.2" 4 | junit = "6.0.0" 5 | opentest4j = "1.3.0" 6 | # plugins 7 | kotlin = "2.2.0" 8 | changelog = "2.2.0" 9 | gradleIntelliJPlugin = "2.10.5" 10 | qodana = "0.1.13" 11 | kover = "0.9.3" 12 | 13 | [libraries] 14 | annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } 15 | junit = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } 16 | opentest4j = { group = "org.opentest4j", name = "opentest4j", version.ref = "opentest4j"} 17 | 18 | [plugins] 19 | changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } 20 | gradleIntelliJPlugin = { id = "org.jetbrains.intellij.platform", version.ref = "gradleIntelliJPlugin" } 21 | kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 22 | kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } 23 | qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } 24 | -------------------------------------------------------------------------------- /testData/completionv2/fieldAnnotated.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Annotated 3 | from pydantic import BaseModel, Field 4 | 5 | class Info: 6 | pass 7 | class A(BaseModel): 8 | abc: Annotated[str, Field(example='example')] 9 | cde: Annotated[str, Field(example='example')] = 'default_value' 10 | efg: Annotated[str, Field(default_factory=lambda: 123)] 11 | a_id: Annotated[str, Field(alias='alias_a_id')] 12 | klm: Annotated[str, Info(), Field(default_factory=lambda: 456)] 13 | nop: Annotated[str, Field(default_factory=lambda: 789), Info()] 14 | default_abc: Annotated[str, Field('example')] 15 | default_efg: Annotated[str, Field(default='123')] 16 | default_klm: Annotated[str, Info(), Field(default='456')] 17 | default_nop: Annotated[str, Field(default='789'), Info()] 18 | default_klm_positional: Annotated[str, Info(), Field('456')] 19 | default_nop_positional: Annotated[str, Field('789'), Info()] 20 | class B(A): 21 | hij: str 22 | 23 | A(). -------------------------------------------------------------------------------- /testData/mock/pydanticv2/config.py: -------------------------------------------------------------------------------- 1 | from typing import TypedDict 2 | 3 | 4 | class _ConfigDict(TypedDict, total=False): 5 | populate_by_name: bool 6 | from_attributes: bool 7 | extra: str 8 | frozen: bool 9 | validate_by_alias: bool 10 | validate_by_name: bool 11 | 12 | 13 | def ConfigDict( 14 | populate_by_name: bool = False, 15 | from_attributes: bool = False, 16 | extra: str = None, 17 | frozen: bool = False, 18 | validate_by_alias: bool = True, 19 | validate_by_name: bool = False, 20 | ) -> _ConfigDict: 21 | return _ConfigDict( 22 | populate_by_name=populate_by_name, 23 | from_attributes=from_attributes, 24 | extra=extra, 25 | frozen=frozen, 26 | validate_by_alias=validate_by_alias, 27 | validate_by_name=validate_by_name, 28 | ) 29 | 30 | 31 | class BaseConfig: 32 | pass 33 | 34 | 35 | class Extra: 36 | allow = 'allow' 37 | ignore = 'ignore' 38 | forbid = 'forbid' 39 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/noDuplicateWarning.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, BaseSettings, dataclass 2 | 3 | 4 | class Model(BaseModel): 5 | value: int 6 | 7 | 8 | @dataclass 9 | class DataclassModel: 10 | value: int 11 | 12 | 13 | class Settings(BaseSettings): 14 | value: int 15 | 16 | 17 | # Pydantic BaseModel: should report a single warning 18 | Model(value='not_int') 19 | 20 | # Pydantic dataclass: should report a single warning 21 | DataclassModel(value='not_int') 22 | 23 | # BaseSettings subclass: should report a single warning 24 | Settings(value='not_int') 25 | 26 | 27 | # Non-Pydantic code should still be checked by the parent inspection 28 | 29 | def func(x: int) -> None: 30 | pass 31 | 32 | 33 | func('string') 34 | -------------------------------------------------------------------------------- /testData/inspection/validatorSelf.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, validator 2 | 3 | def check(func): 4 | def inner(): 5 | func() 6 | return inner 7 | 8 | class A(BaseModel): 9 | a: str 10 | b: str 11 | c: str 12 | d: str 13 | e: str 14 | 15 | @validator('a') 16 | def validate_a(self): 17 | pass 18 | 19 | @validator('b') 20 | def validate_b(fles): 21 | pass 22 | 23 | @validator('c') 24 | def validate_b(*args): 25 | pass 26 | 27 | @validator('d') 28 | def validate_c(**kwargs): 29 | pass 30 | 31 | @validator('e') 32 | def validate_e(): 33 | pass 34 | 35 | def dummy(self): 36 | pass 37 | 38 | @check 39 | def task(self): 40 | pass -------------------------------------------------------------------------------- /resources/META-INF/python-common.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/__init__.py: -------------------------------------------------------------------------------- 1 | from pydantic_core import ValidationError 2 | from pydantic_core.core_schema import ( 3 | FieldSerializationInfo, 4 | FieldValidationInfo, 5 | SerializationInfo, 6 | SerializerFunctionWrapHandler, 7 | ValidationInfo, 8 | ValidatorFunctionWrapHandler, 9 | ) 10 | from .field_validator import field_validator, model_validator 11 | from . import dataclasses 12 | from .analyzed_type import AnalyzedType 13 | from .config import BaseConfig, ConfigDict, Extra 14 | from .decorator import validate_arguments 15 | from .functional_validators import field_serializer, field_validator, model_serializer, root_validator, validator, model_validator 16 | from .errors import * 17 | from .fields import Field, PrivateAttr 18 | from .main import * 19 | from .networks import * 20 | from .tools import * 21 | from .types import * 22 | from .config import ConfigDict 23 | from .version import VERSION 24 | from .deprecated import validator, root_validator 25 | from .root_model import RootModel 26 | 27 | __version__ = VERSION 28 | -------------------------------------------------------------------------------- /.run/Run IDE for UI Tests.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 15 | 17 | true 18 | true 19 | false 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/mypy-compatible.md: -------------------------------------------------------------------------------- 1 | # Mypy Compatible 2 | 3 | !!! info 4 | **This feature is in version 0.1.4 or later** 5 | 6 | This plugin is compatible with the [pydantic-mypy plugin](https://pydantic-docs.helpmanual.io/mypy_plugin/), which is included in pydantic package. 7 | 8 | If you set supported features in mypy.ini then, the pycharm plugin performs the same inspects. 9 | 10 | ## Support features 11 | - init_typed 12 | - warn_untyped_fields 13 | 14 | ### init_typed 15 | If enabled, include the field types as type hints in the generated signature for the __init__ method. This means that you'll get errors if you pass an argument that is not already the right type to __init__, even if parsing could safely convert the type. 16 | 17 | ### warn_untyped_fields 18 | If enabled, raise an error whenever a field is declared on a model without explicitly specifying its type. 19 | 20 | 21 | ## Settings 22 | 23 | You can toggle these features in PyCharm's Settings. 24 | 25 | ![settings 1](settings1.png) 26 | 27 | !!! tips 28 | **If there is mypy.ini in your project, this plugin use values in mypy.ini** 29 | -------------------------------------------------------------------------------- /.run/Run IDE with Plugin.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Run Plugin Tests.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticIgnoreInspection.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.psi.PsiReference 4 | import com.jetbrains.python.inspections.PyInspectionExtension 5 | import com.jetbrains.python.psi.* 6 | import com.jetbrains.python.psi.types.TypeEvalContext 7 | 8 | class PydanticIgnoreInspection : PyInspectionExtension() { 9 | override fun ignoreUnresolvedReference( 10 | node: PyElement, 11 | reference: PsiReference, 12 | context: TypeEvalContext 13 | ): Boolean { 14 | if (node !is PyStringLiteralExpression) return false 15 | return isValidatorField(node, context) 16 | 17 | 18 | } 19 | 20 | override fun ignoreMethodParameters(function: PyFunction, context: TypeEvalContext): Boolean { 21 | val pyClass = function.containingClass ?: return false 22 | if (!isPydanticModel(pyClass, true, context)) return false 23 | if (!function.hasValidatorMethod(PydanticCacheService.getVersion(function.project))) return false 24 | if (function.hasModelValidatorModeAfter()) return false 25 | return true 26 | } 27 | } -------------------------------------------------------------------------------- /.run/Run Qodana.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 16 | 19 | 21 | true 22 | true 23 | false 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Koudai Aono 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /testData/typecheckerinspection/fieldImportTypingInvalid.py: -------------------------------------------------------------------------------- 1 | 2 | import typing 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class A(BaseModel): 8 | a: typing.Union[int, str, None] 9 | b: typing.Optional[str] 10 | c: typing.Annotated[str, Field(example='abc')] 11 | d: typing.Any 12 | 13 | A(a=bytes(123), b=bytes(456), c=bytes(789), d=bytes(987)) 14 | A(a=bytes(123), b=bytes(456), c=bytes(789), d=bytes(987)) 15 | A(a=bytes(123), b=bytes(456), c=bytes(789), d=bytes(987)) -------------------------------------------------------------------------------- /testData/inspectionv2/modelAttribute.py: -------------------------------------------------------------------------------- 1 | from typing import ClassVar 2 | import dataclasses 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class B(BaseModel): 8 | class Inner(BaseModel): 9 | user: str 10 | a: int = 1 11 | _url: str = "https://someurl" 12 | TEST: ClassVar[str] = "Hello World" 13 | def f(self): 14 | self._url 15 | self.Inner 16 | self.fake 17 | self.a 18 | B.a 19 | b = B(a=1) 20 | b.fake 21 | B.Inner 22 | B.__name__ 23 | b.__name__ 24 | class C(B): 25 | c: int = 1 26 | def ff(self): 27 | self.fake 28 | self.a 29 | self.c 30 | self._url 31 | c = C(a=1, c=1) 32 | c.a 33 | C._url 34 | c._url 35 | c.b 36 | print(B.TEST) 37 | print(C.TEST) 38 | C.Inner 39 | C.model_fields 40 | c.model_fields 41 | -------------------------------------------------------------------------------- /testData/inspection/ormMode.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | pass 6 | A.from_orm('') 7 | 8 | class B(BaseModel): 9 | class Config: 10 | orm_mode=False 11 | B.from_orm('') 12 | 13 | 14 | class C(BaseModel): 15 | class Config: 16 | orm_mode=True 17 | C.from_orm('') 18 | 19 | class C(BaseModel): 20 | class Config: 21 | orm_mode=False 22 | C.from_orm('') 23 | 24 | orm_mode = True 25 | class D(BaseModel): 26 | class Config: 27 | orm_mode=orm_mode 28 | D.from_orm('') 29 | 30 | 31 | class E(D): 32 | class Config: 33 | orm_mode=False 34 | E.from_orm('') 35 | 36 | class A(BaseModel): 37 | def __call__(self, *args, **kwargs): 38 | class Inner: 39 | @classmethod 40 | def from_orm(self, *args, **kwargs): 41 | pass 42 | return Inner 43 | 44 | A()().from_orm('') 45 | -------------------------------------------------------------------------------- /testData/typeinspectionv18/overrideInit.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | def __init__(self): 7 | pass 8 | A() 9 | 10 | class B(BaseModel): 11 | abc: str = '123' 12 | def __init__(self, a: float, b: int): 13 | pass 14 | B(abc='123') 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | def __init__(self, a: float, b: int = 123): 19 | pass 20 | 21 | C(abc='123') 22 | 23 | 24 | # class D(BaseModel): 25 | # abc: str = '123' 26 | # def __init__(self, *a): 27 | # pass 28 | # 29 | # C(abc='123') 30 | # 31 | # class E(BaseModel): 32 | # abc: str = '123' 33 | # def __init__(self, **a): 34 | # pass 35 | # E(abc='123') 36 | 37 | class F(C): 38 | abc: str = '123' 39 | 40 | def __init__(self, c: float, d: str): 41 | super(F, self).__init__(...) 42 | F(abc='123') 43 | 44 | class G(C): 45 | abc: str = '123' 46 | 47 | def __new__(self, c: float, d: str): 48 | super(F, self).__init__(...) 49 | G(abc='123') 50 | 51 | 52 | class H(C): 53 | pass 54 | 55 | H(abc='123') 56 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticDataclassInspectionSuppressor.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.codeInspection.InspectionSuppressor 4 | import com.intellij.codeInspection.SuppressQuickFix 5 | import com.intellij.psi.PsiElement 6 | import com.intellij.psi.PsiFile 7 | import com.intellij.psi.util.PsiTreeUtil 8 | import com.jetbrains.python.psi.PyClass 9 | import com.jetbrains.python.psi.PyFile 10 | import com.jetbrains.python.psi.types.TypeEvalContext 11 | 12 | class PydanticDataclassInspectionSuppressor : InspectionSuppressor { 13 | 14 | override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean { 15 | if (element is PsiFile) return false 16 | if (element.containingFile !is PyFile) return false 17 | if (toolId != "PyDataclass") return false 18 | 19 | val pyClass = PsiTreeUtil.getParentOfType(element, PyClass::class.java, false) ?: return false 20 | 21 | val context = TypeEvalContext.codeAnalysis(pyClass.project, pyClass.containingFile) 22 | return isPydanticModel(pyClass, false, context) 23 | } 24 | 25 | override fun getSuppressActions(element: PsiElement?, toolId: String): Array { 26 | return SuppressQuickFix.EMPTY_ARRAY 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticTypeInspectionV18Test.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import com.jetbrains.python.inspections.PyTypeCheckerInspection 5 | import kotlin.reflect.KClass 6 | 7 | 8 | open class PydanticTypeInspectionV18Test : PydanticInspectionBase("v18") { 9 | 10 | @Suppress("UNCHECKED_CAST") 11 | override val inspectionClass: KClass = PyTypeCheckerInspection::class as KClass 12 | // TODO: Dynamic model type checking broken in PyCharm 2025.2 13 | fun _disabled_testDynamicModel() { 14 | doTest() 15 | } 16 | 17 | // TODO: Dataclass type checking broken in PyCharm 2025.2 18 | fun _disabled_testDataclass() { 19 | doTest() 20 | } 21 | 22 | fun testBaseSetting() { 23 | doTest() 24 | } 25 | 26 | // TODO: Generic type resolution for pydantic.generics.GenericModel not working in PyCharm 2025.2 27 | // This complex test with GenericModel from pydantic v1.8 is temporarily disabled 28 | fun _disabled_testGenericModel() { 29 | doTest() 30 | } 31 | 32 | // TODO: SQLModel type checking broken in PyCharm 2025.2 33 | fun _disabled_testSqlModel() { 34 | doTest() 35 | } 36 | } -------------------------------------------------------------------------------- /.run/Run Plugin Verification.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 25 | 26 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/deprecated/class_validators.py: -------------------------------------------------------------------------------- 1 | from warnings import warn 2 | 3 | from ..warnings import PydanticDeprecatedSince20 4 | 5 | DeprecationWarning = PydanticDeprecatedSince20 6 | 7 | 8 | def validator( 9 | __field: str, 10 | *fields: str, 11 | pre: bool = False, 12 | each_item: bool = False, 13 | always: bool = False, 14 | check_fields: bool | None = None, 15 | allow_reuse: bool = False, 16 | ) -> Callable[[_V1ValidatorType], _V1ValidatorType]: 17 | 18 | warn( 19 | 'Pydantic V1 style `@validator` validators are deprecated.' 20 | ' You should migrate to Pydantic V2 style `@field_validator` validators,' 21 | ' see the migration guide for more details', 22 | DeprecationWarning, 23 | stacklevel=2, 24 | ) 25 | 26 | 27 | def root_validator( 28 | *__args, 29 | pre: bool = False, 30 | skip_on_failure: bool = False, 31 | allow_reuse: bool = False, 32 | ) -> Any: 33 | warn( 34 | 'Pydantic V1 style `@root_validator` validators are deprecated.' 35 | ' You should migrate to Pydantic V2 style `@model_validator` validators,' 36 | ' see the migration guide for more details', 37 | DeprecationWarning, 38 | stacklevel=2, 39 | ) 40 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.openapi.options.Configurable 4 | import com.intellij.openapi.project.Project 5 | import javax.swing.JComponent 6 | 7 | 8 | class PydanticConfigurable internal constructor(project: Project) : Configurable { 9 | private val pydanticConfigService: PydanticConfigService = PydanticConfigService.getInstance(project) 10 | private val configPanel: PydanticConfigPanel = PydanticConfigPanel(project) 11 | override fun getDisplayName(): String { 12 | return "Pydantic" 13 | } 14 | 15 | override fun getHelpTopic(): String? { 16 | return null 17 | } 18 | 19 | override fun createComponent(): JComponent { 20 | reset() 21 | return configPanel.configPanel 22 | } 23 | 24 | override fun reset() {} 25 | 26 | override fun isModified(): Boolean { 27 | return (pydanticConfigService.initTyped != configPanel.initTyped) || 28 | (pydanticConfigService.warnUntypedFields != configPanel.warnUntypedFields) 29 | } 30 | 31 | override fun apply() { 32 | pydanticConfigService.initTyped = configPanel.initTyped 33 | pydanticConfigService.warnUntypedFields = configPanel.warnUntypedFields 34 | } 35 | 36 | override fun disposeUIResources() { 37 | } 38 | } -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | **The plugin requires PyCharm 2020.2 or later (include other JetBrains IDEs)** 4 | 5 | ## MarketPlace 6 | The plugin is in Jetbrains repository ([Pydantic Plugin Page](https://plugins.jetbrains.com/plugin/12861-pydantic)) 7 | 8 | You can install the stable version on PyCharm's `Marketplace` (Preference -> Plugins -> Marketplace) [Official Documentation](https://www.jetbrains.com/help/idea/managing-plugins.html) 9 | 10 | ![search plugin](search_plugin.png) 11 | 12 | ## Complied binary 13 | The ['Releases'](https://github.com/koxudaxi/pydantic-pycharm-plugin/releases) section of this repository contains a compiled version of the plugin: [pydantic-pycharm-plugin.zip(latest)](https://github.com/koxudaxi/pydantic-pycharm-plugin/releases/latest/download/pydantic-pycharm-plugin.zip) 14 | 15 | After downloading this file, you can install the plugin from disk by following [the JetBrains instructions here](https://www.jetbrains.com/help/pycharm/plugins-settings.html). 16 | 17 | ## Source 18 | Alternatively, you can clone this repository and follow the instructions under the "Building the plugin" heading below to build from source. 19 | The build process will create the file `build/distributions/pydantic-pycharm-plugin.zip`. 20 | This file can be installed as a PyCharm plugin from disk following the same instructions. 21 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticDataclassTypeProvider.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.jetbrains.python.codeInsight.stdlib.PyDataclassTypeProvider 5 | import com.jetbrains.python.psi.* 6 | import com.jetbrains.python.psi.impl.PyCallExpressionImpl 7 | import com.jetbrains.python.psi.types.* 8 | 9 | /** 10 | * `PydanticDataclassTypeProvider` gets actual pydantic dataclass types 11 | * 12 | * PyCharm 2021.1 detects decorated object type by type-hint of decorators. 13 | * Unfortunately, pydantic.dataclasses.dataclass returns `Dataclass` type. 14 | * `Dataclass` is not an actual model, which is Stub type for static-type checking. 15 | * But, PyCharm can detect actual dataclass type by parsing the type definition. 16 | * `PydanticDataclassTypeProvider` ignore `Dataclass` and get actual dataclass type using `PyDataclassTypeProvider` 17 | * 18 | */ 19 | class PydanticDataclassTypeProvider : PyTypeProviderBase() { 20 | override fun getCallableType(callable: PyCallable, context: TypeEvalContext): PyType? { 21 | if (callable is PyFunction && callable.isPydanticDataclass) { 22 | // Drop fake dataclass return type 23 | return PyCallableTypeImpl(callable.getParameters(context), null) 24 | } 25 | return super.getCallableType(callable, context) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testData/inspectionv18/readOnlyPropertyFrozen.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | A.abc = '456' 7 | A().abc = '456' 8 | 9 | class B(BaseModel): 10 | abc: str = '123' 11 | class Config: 12 | frozen=True 13 | B.abc = '456' 14 | B().abc = '456' 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | class Config: 19 | frozen=False 20 | C.abc = '456' 21 | C().abc = '456' 22 | 23 | class D(BaseModel): 24 | class Config: 25 | frozen=True 26 | D.abc = '456' 27 | D().abc = '456' 28 | 29 | frozen = False 30 | class E(BaseModel): 31 | class Config: 32 | frozen=frozen 33 | E.abc = '456' 34 | E().abc = '456' 35 | 36 | 37 | class F(D): 38 | class Config: 39 | frozen=True 40 | F.abc = '456' 41 | F().abc = '456' 42 | 43 | 44 | class G(BaseModel): 45 | class Config: 46 | frozen=False 47 | G.abc = 48 | G.abc = "test" 49 | G.abc.lower() 50 | G.abc.lower() = 'efg' 51 | 52 | class H: 53 | class Config: 54 | frozen=True 55 | H.abc = '123' -------------------------------------------------------------------------------- /testData/inspectionv2/readOnlyPropertyFrozenConfig.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | A.abc = '456' 7 | A().abc = '456' 8 | 9 | class B(BaseModel): 10 | abc: str = '123' 11 | class Config: 12 | frozen=True 13 | B.abc = '456' 14 | B().abc = '456' 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | class Config: 19 | frozen=False 20 | C.abc = '456' 21 | C().abc = '456' 22 | 23 | class D(BaseModel): 24 | class Config: 25 | frozen=True 26 | D.abc = '456' 27 | D().abc = '456' 28 | 29 | frozen = False 30 | class E(BaseModel): 31 | class Config: 32 | frozen=frozen 33 | E.abc = '456' 34 | E().abc = '456' 35 | 36 | 37 | class F(D): 38 | class Config: 39 | frozen=True 40 | F.abc = '456' 41 | F().abc = '456' 42 | 43 | 44 | class G(BaseModel): 45 | class Config: 46 | frozen=False 47 | G.abc = 48 | G.abc = "test" 49 | G.abc.lower() 50 | G.abc.lower() = 'efg' 51 | 52 | 53 | class H: 54 | class Config: 55 | frozen=True 56 | H.abc = '123' 57 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/generics.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | TYPE_CHECKING, 3 | Any, 4 | ClassVar, 5 | Dict, 6 | Generic, 7 | Iterator, 8 | List, 9 | Mapping, 10 | Optional, 11 | Tuple, 12 | Type, 13 | TypeVar, 14 | Union, 15 | cast, 16 | get_type_hints, 17 | ) 18 | 19 | from .main import BaseModel 20 | 21 | _generic_types_cache: Dict[Tuple[Type[Any], Union[Any, Tuple[Any, ...]]], Type[BaseModel]] = {} 22 | GenericModelT = TypeVar('GenericModelT', bound='GenericModel') 23 | TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type 24 | 25 | 26 | class GenericModel(BaseModel): 27 | __slots__ = () 28 | __concrete__: ClassVar[bool] = False 29 | 30 | if TYPE_CHECKING: 31 | # Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with 32 | # `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of 33 | # `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below. 34 | __parameters__: ClassVar[Tuple[TypeVarType, ...]] 35 | 36 | # Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings 37 | def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]: 38 | pass -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html 2 | 3 | pluginGroup = com.koxudaxi.pydantic 4 | pluginName = Pydantic 5 | pluginRepositoryUrl = https://github.com/koxudaxi/pydantic-pycharm-plugin 6 | # SemVer format -> https://semver.org 7 | pluginVersion = 0.4.23 8 | 9 | # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html 10 | pluginSinceBuild = 253.28294.336 11 | pluginUntilBuild = 253.* 12 | 13 | # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension 14 | platformType = PC 15 | platformVersion = 2025.3 16 | 17 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 18 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 19 | platformPlugins = 20 | platformBundledPlugins = org.toml.lang 21 | # Gradle Releases -> https://github.com/gradle/gradle/releases 22 | gradleVersion = 8.13 23 | 24 | # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib 25 | kotlin.stdlib.default.dependency = true 26 | 27 | org.gradle.unsafe.configuration-cache = false 28 | 29 | # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html 30 | org.gradle.caching = true 31 | -------------------------------------------------------------------------------- /testData/inspectionv18/readOnlyProperty.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | A.abc = '456' 7 | A().abc = '456' 8 | 9 | class B(BaseModel): 10 | abc: str = '123' 11 | class Config: 12 | allow_mutation=False 13 | B.abc = '456' 14 | B().abc = '456' 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | class Config: 19 | allow_mutation=True 20 | C.abc = '456' 21 | C().abc = '456' 22 | 23 | class D(BaseModel): 24 | class Config: 25 | allow_mutation=False 26 | D.abc = '456' 27 | D().abc = '456' 28 | 29 | allow_mutation = True 30 | class E(BaseModel): 31 | class Config: 32 | allow_mutation=allow_mutation 33 | E.abc = '456' 34 | E().abc = '456' 35 | 36 | 37 | class F(D): 38 | class Config: 39 | allow_mutation=False 40 | F.abc = '456' 41 | F().abc = '456' 42 | 43 | 44 | class G(BaseModel): 45 | class Config: 46 | allow_mutation=False 47 | G.abc = 48 | G.abc = "test" 49 | G.abc.lower() 50 | G.abc.lower() = 'efg' 51 | 52 | class H: 53 | class Config: 54 | allow_mutation=False 55 | H.abc = '123' -------------------------------------------------------------------------------- /testData/inspectionv18/defaultFactory.py: -------------------------------------------------------------------------------- 1 | from dataclasses import field 2 | 3 | from pydantic import BaseModel, Field 4 | from pydantic.dataclasses import dataclass 5 | 6 | def get_int() -> int: 7 | pass 8 | 9 | def get_str() -> str: 10 | pass 11 | 12 | class A(BaseModel): 13 | a: int = Field(default_factory=lambda: 1) 14 | b: str = Field(default_factory=lambda: 1) 15 | c: str = Field(default_factory=get_str) 16 | d: str = Field(default_factory=get_int) 17 | 18 | @dataclass 19 | class B: 20 | a: int = Field(default_factory=lambda: 1) 21 | b: str = Field(default_factory=lambda: 1) 22 | c: str = Field(default_factory=get_str) 23 | d: str = Field(default_factory=get_int) 24 | e: int = field(default_factory=lambda: 1) 25 | f: str = field(default_factory=lambda: 1) 26 | g: str = Field(default_factory=get_str) 27 | h: str = field(default_factory=get_int) 28 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticDynamicModelMemberProvider.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.jetbrains.python.codeInsight.PyCustomMember 5 | import com.jetbrains.python.psi.resolve.PyResolveContext 6 | import com.jetbrains.python.psi.types.PyClassMembersProviderBase 7 | import com.jetbrains.python.psi.types.PyClassType 8 | import com.jetbrains.python.psi.types.TypeEvalContext 9 | 10 | class PydanticDynamicModelMemberProvider : PyClassMembersProviderBase() { 11 | override fun resolveMember( 12 | type: PyClassType, 13 | name: String, 14 | location: PsiElement?, 15 | resolveContext: PyResolveContext, 16 | ): PsiElement? { 17 | val pyClass = type.pyClass 18 | if (pyClass is PydanticDynamicModel && !type.isDefinition) 19 | pyClass.resolveMember(name)?.let { return it } 20 | return super.resolveMember(type, name, location, resolveContext) 21 | } 22 | 23 | override fun getMembers( 24 | clazz: PyClassType?, 25 | location: PsiElement?, 26 | context: TypeEvalContext, 27 | ): MutableCollection { 28 | if (clazz == null || clazz.isDefinition) return mutableListOf() 29 | val pyClass = clazz.pyClass 30 | return if (pyClass is PydanticDynamicModel) { 31 | pyClass.members.toMutableList() 32 | } else { 33 | mutableListOf() 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticPyNestedDecoratorsInspectionSuppressor.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.codeInspection.InspectionSuppressor 4 | import com.intellij.codeInspection.SuppressQuickFix 5 | import com.intellij.psi.PsiElement 6 | import com.intellij.psi.PsiFile 7 | import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider 8 | import com.jetbrains.python.psi.PyBinaryExpression 9 | import com.jetbrains.python.psi.PyDecorator 10 | import com.jetbrains.python.psi.PyFile 11 | import com.jetbrains.python.psi.PySubscriptionExpression 12 | import com.jetbrains.python.psi.PyTypedElement 13 | import com.jetbrains.python.psi.types.TypeEvalContext 14 | 15 | class PydanticPyNestedDecoratorsInspectionSuppressor : InspectionSuppressor { 16 | 17 | override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean { 18 | if (element is PsiFile) return false 19 | if (element.containingFile !is PyFile) return false 20 | if (toolId !in inspectionsToSuppress) return false 21 | if (element !is PyDecorator) return false 22 | return element.include(MODEL_VALIDATOR_QUALIFIED_NAMES) 23 | } 24 | 25 | override fun getSuppressActions(element: PsiElement?, toolId: String): Array { 26 | return SuppressQuickFix.EMPTY_ARRAY 27 | } 28 | 29 | companion object { 30 | private val inspectionsToSuppress = listOf( 31 | "PyNestedDecorators" 32 | ) 33 | } 34 | } -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticInspectionV2Test.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.jetbrains.python.inspections.PyInspection 4 | import kotlin.reflect.KClass 5 | 6 | 7 | open class PydanticInspectionV2Test : PydanticInspectionBase(version = "v2") { 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | override val inspectionClass: KClass = PydanticInspection::class as KClass 11 | 12 | fun testCustomRoot() { 13 | val pydanticConfigService = PydanticConfigService.getInstance(myFixture!!.project) 14 | pydanticConfigService.mypyWarnUntypedFields = false 15 | doTest() 16 | } 17 | fun testValidatorSelf() { 18 | doTest() 19 | } 20 | 21 | fun testReadOnlyPropertyFrozenConfig() { 22 | doTest() 23 | } 24 | 25 | fun testReadOnlyPropertyFrozenConfigDict() { 26 | doTest() 27 | } 28 | 29 | fun testValidators() { 30 | doTest() 31 | } 32 | 33 | fun testValidatorField() { 34 | doTest() 35 | } 36 | 37 | fun testAnnotated() { 38 | doTest() 39 | } 40 | fun testModelAttribute() { 41 | doTest() 42 | } 43 | 44 | fun testPrivateFieldDataclassTransform() { 45 | doTest() 46 | } 47 | 48 | fun testPrivateFieldsBaseModelAlias() { 49 | doTest() 50 | } 51 | 52 | fun testExtra() { 53 | doTest() 54 | } 55 | 56 | fun testFrozenClassArgument() { 57 | doTest() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /testData/inspectionv2/validatorSelf.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, field_validator, model_validator 2 | 3 | def check(func): 4 | def inner(): 5 | func() 6 | return inner 7 | 8 | class A(BaseModel): 9 | a: str 10 | b: str 11 | c: str 12 | d: str 13 | e: str 14 | 15 | @field_validator('a') 16 | def validate_a(self): 17 | pass 18 | 19 | @field_validator('b') 20 | def validate_b(fles): 21 | pass 22 | 23 | @field_validator('c') 24 | def validate_b(*args): 25 | pass 26 | 27 | @field_validator('d') 28 | def validate_c(**kwargs): 29 | pass 30 | 31 | @field_validator('e') 32 | def validate_e(): 33 | pass 34 | 35 | @model_validator() 36 | def validate_model(): 37 | pass 38 | 39 | @model_validator(mode='after') 40 | def validate_model_after(self): 41 | pass 42 | 43 | @model_validator(mode='before') 44 | def validate_model_before(): 45 | pass 46 | def dummy(self): 47 | pass 48 | 49 | @check 50 | def task(self): 51 | pass -------------------------------------------------------------------------------- /testData/inspection/readOnlyProperty.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | A.abc = '456' 7 | A().abc = '456' 8 | 9 | class B(BaseModel): 10 | abc: str = '123' 11 | class Config: 12 | allow_mutation=False 13 | B.abc = '456' 14 | B().abc = '456' 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | class Config: 19 | allow_mutation=True 20 | C.abc = '456' 21 | C().abc = '456' 22 | 23 | class D(BaseModel): 24 | class Config: 25 | allow_mutation=False 26 | D.abc = '456' 27 | D().abc = '456' 28 | 29 | allow_mutation = True 30 | class E(BaseModel): 31 | class Config: 32 | allow_mutation=allow_mutation 33 | E.abc = '456' 34 | E().abc = '456' 35 | 36 | 37 | class F(D): 38 | class Config: 39 | allow_mutation=False 40 | F.abc = '456' 41 | F().abc = '456' 42 | 43 | 44 | class G(BaseModel): 45 | class Config: 46 | allow_mutation=False 47 | G.abc = 48 | G.abc = "test" 49 | G.abc.lower() 50 | G.abc.lower() = 'efg' 51 | 52 | class H: 53 | class Config: 54 | allow_mutation=False 55 | H.abc = '123' 56 | 57 | class I(BaseModel): 58 | abc: str = '123' 59 | class Config: 60 | frozen=False 61 | I.abc = '456' -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticSdkChangeWatcher.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.ProjectTopics 4 | import com.intellij.openapi.project.Project 5 | import com.intellij.openapi.projectRoots.Sdk 6 | import com.intellij.openapi.roots.ModuleRootEvent 7 | import com.intellij.openapi.roots.ModuleRootListener 8 | import com.jetbrains.python.sdk.pythonSdk 9 | import com.jetbrains.python.statistics.modules 10 | 11 | class PydanticSdkChangeWatcher(private val project: Project) { 12 | private var sdkFingerprint: String? = computeSdkFingerprint() 13 | 14 | init { 15 | project.messageBus.connect(project).subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener { 16 | override fun rootsChanged(event: ModuleRootEvent) { 17 | val current = computeSdkFingerprint() 18 | if (current != sdkFingerprint) { 19 | sdkFingerprint = current 20 | PydanticCacheService.clear(project) 21 | } 22 | } 23 | }) 24 | } 25 | 26 | private fun computeSdkFingerprint(): String? { 27 | val sdkFingerprints = project.modules 28 | .mapNotNull { it.pythonSdk?.sdkFingerprint } 29 | .sorted() 30 | val fingerprint = when { 31 | sdkFingerprints.isNotEmpty() -> sdkFingerprints.joinToString("|") 32 | else -> project.sdk?.sdkFingerprint 33 | } 34 | return fingerprint 35 | } 36 | } 37 | 38 | private val Sdk.sdkFingerprint: String 39 | get() = homePath ?: name 40 | -------------------------------------------------------------------------------- /testData/mock/pydanticv1/main.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | from enum import Enum 4 | 5 | 6 | class BaseModel: 7 | class Config: 8 | pass 9 | 10 | ___slots__ = () 11 | 12 | @classmethod 13 | def from_orm(cls, obj): 14 | pass 15 | 16 | 17 | class Extra(str, Enum): 18 | allow = 'allow' 19 | ignore = 'ignore' 20 | forbid = 'forbid' 21 | 22 | class GetterDict: 23 | pass 24 | 25 | 26 | class json: 27 | def loads(self): 28 | pass 29 | 30 | def dumps(self): 31 | pass 32 | 33 | 34 | class BaseConfig: 35 | title = None 36 | anystr_strip_whitespace = False 37 | min_anystr_length = None 38 | max_anystr_length = None 39 | validate_all = False 40 | extra = Extra.ignore 41 | allow_mutation = True 42 | allow_population_by_field_name = False 43 | use_enum_values = False 44 | fields = {} 45 | validate_assignment = False 46 | error_msg_templates = {} 47 | arbitrary_types_allowed = False 48 | orm_mode: bool = False 49 | getter_dict = GetterDict 50 | alias_generator = None 51 | keep_untouched = () 52 | schema_extra = {} 53 | json_loads = json.loads 54 | json_dumps = json.dumps 55 | json_encoders = {} 56 | 57 | def create_model( 58 | model_name: str, 59 | *, 60 | __config__: Type[BaseConfig] = None, 61 | __base__: Type[BaseModel] = None, 62 | __module__: Optional[str] = None, 63 | __validators__: Dict[str, classmethod] = None, 64 | **field_definitions: Any, 65 | ) -> Type[BaseModel]: 66 | pass -------------------------------------------------------------------------------- /testData/mock/pydanticv18/main.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | class BaseModel: 4 | class Config: 5 | pass 6 | 7 | ___slots__ = () 8 | 9 | @classmethod 10 | def from_orm(cls, obj): 11 | pass 12 | 13 | Model = TypeVar('Model', bound='BaseModel') 14 | 15 | 16 | class Extra(str): 17 | allow = 'allow' 18 | ignore = 'ignore' 19 | forbid = 'forbid' 20 | 21 | class GetterDict: 22 | pass 23 | 24 | 25 | class json: 26 | def loads(self): 27 | pass 28 | 29 | def dumps(self): 30 | pass 31 | 32 | 33 | class BaseConfig: 34 | title = None 35 | anystr_strip_whitespace = False 36 | min_anystr_length = None 37 | max_anystr_length = None 38 | validate_all = False 39 | extra = Extra.ignore 40 | allow_mutation = True 41 | frozen = False 42 | allow_population_by_field_name = False 43 | use_enum_values = False 44 | fields = {} 45 | validate_assignment = False 46 | error_msg_templates = {} 47 | arbitrary_types_allowed = False 48 | orm_mode: bool = False 49 | getter_dict = GetterDict 50 | alias_generator = None 51 | keep_untouched = () 52 | schema_extra = {} 53 | json_loads = json.loads 54 | json_dumps = json.dumps 55 | json_encoders = {} 56 | 57 | def create_model( 58 | __model_name: str, 59 | *, 60 | __config__: Type[BaseConfig] = None, 61 | __base__: Type['Model'] = None, 62 | __module__: str = __name__, 63 | __validators__: Dict[str, classmethod] = None, 64 | **field_definitions: Any, 65 | ) -> Type['Model']: 66 | pass -------------------------------------------------------------------------------- /testData/mock/pydanticv2/v1/main.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | from enum import Enum 4 | 5 | 6 | class BaseModel: 7 | class Config: 8 | pass 9 | 10 | ___slots__ = () 11 | 12 | @classmethod 13 | def from_orm(cls, obj): 14 | pass 15 | 16 | 17 | class Extra(str, Enum): 18 | allow = 'allow' 19 | ignore = 'ignore' 20 | forbid = 'forbid' 21 | 22 | class GetterDict: 23 | pass 24 | 25 | 26 | class json: 27 | def loads(self): 28 | pass 29 | 30 | def dumps(self): 31 | pass 32 | 33 | 34 | class BaseConfig: 35 | title = None 36 | anystr_strip_whitespace = False 37 | min_anystr_length = None 38 | max_anystr_length = None 39 | validate_all = False 40 | extra = Extra.ignore 41 | allow_mutation = True 42 | allow_population_by_field_name = False 43 | use_enum_values = False 44 | fields = {} 45 | validate_assignment = False 46 | error_msg_templates = {} 47 | arbitrary_types_allowed = False 48 | orm_mode: bool = False 49 | getter_dict = GetterDict 50 | alias_generator = None 51 | keep_untouched = () 52 | schema_extra = {} 53 | json_loads = json.loads 54 | json_dumps = json.dumps 55 | json_encoders = {} 56 | 57 | def create_model( 58 | model_name: str, 59 | *, 60 | __config__: Type[BaseConfig] = None, 61 | __base__: Type[BaseModel] = None, 62 | __module__: Optional[str] = None, 63 | __validators__: Dict[str, classmethod] = None, 64 | **field_definitions: Any, 65 | ) -> Type[BaseModel]: 66 | pass 67 | -------------------------------------------------------------------------------- /testData/mock/pydanticv2/fields.py: -------------------------------------------------------------------------------- 1 | 2 | def Field( # noqa: C901 3 | default: Any = PydanticUndefined, 4 | *, 5 | default_factory: typing.Callable[[], Any] | None = _Unset, 6 | alias: str | None = _Unset, 7 | alias_priority: int | None = _Unset, 8 | validation_alias: str | AliasPath | AliasChoices | None = _Unset, 9 | serialization_alias: str | None = _Unset, 10 | title: str | None = _Unset, 11 | description: str | None = _Unset, 12 | examples: list[Any] | None = _Unset, 13 | exclude: bool | None = _Unset, 14 | discriminator: str | None = _Unset, 15 | json_schema_extra: dict[str, Any] | typing.Callable[[dict[str, Any]], None] | None = _Unset, 16 | frozen: bool | None = _Unset, 17 | validate_default: bool | None = _Unset, 18 | repr: bool = _Unset, 19 | init_var: bool | None = _Unset, 20 | kw_only: bool | None = _Unset, 21 | pattern: str | None = _Unset, 22 | strict: bool | None = _Unset, 23 | gt: float | None = _Unset, 24 | ge: float | None = _Unset, 25 | lt: float | None = _Unset, 26 | le: float | None = _Unset, 27 | multiple_of: float | None = _Unset, 28 | allow_inf_nan: bool | None = _Unset, 29 | max_digits: int | None = _Unset, 30 | decimal_places: int | None = _Unset, 31 | min_length: int | None = _Unset, 32 | max_length: int | None = _Unset, 33 | union_mode: Literal['smart', 'left_to_right'] = _Unset, 34 | **extra: Unpack[_EmptyKwargs], 35 | ) -> Any: 36 | pass -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticRegexTest.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.lang.injection.InjectedLanguageManager 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiLanguageInjectionHost 6 | import com.intellij.psi.util.PsiUtilBase.getElementAtCaret 7 | 8 | class PydanticRegexTest : PydanticTestCase() { 9 | fun testConstr() { 10 | doTestInjectedText("[^a-zA-Z]+") 11 | } 12 | 13 | fun testField() { 14 | doTestInjectedText("[^a-zA-Z]+") 15 | } 16 | 17 | fun testConstrMinLength() { 18 | doTestInjectedText(null) 19 | } 20 | 21 | fun testFieldTitle() { 22 | doTestInjectedText(null) 23 | } 24 | 25 | fun testFieldDefault() { 26 | doTestInjectedText(null) 27 | } 28 | 29 | fun testOtherFunc() { 30 | doTestInjectedText(null) 31 | } 32 | 33 | private fun doTestInjectedText(expected: String?): PsiElement? { 34 | configureByFile() 35 | val languageManager = InjectedLanguageManager.getInstance(myFixture!!.project) 36 | val host: PsiLanguageInjectionHost? = languageManager.getInjectionHost(getElementAtCaret(myFixture!!.editor)!!) 37 | if (expected == null) { 38 | assertNull(host) 39 | return null 40 | } 41 | assertNotNull(host) 42 | val files = languageManager.getInjectedPsiFiles(host!!) 43 | assertNotNull(files) 44 | assertFalse(files!!.isEmpty()) 45 | val injected = files[0].getFirst() 46 | assertEquals(expected, injected.text) 47 | return injected 48 | } 49 | } -------------------------------------------------------------------------------- /testData/inspectionv2/customRoot.py: -------------------------------------------------------------------------------- 1 | from typing import ClassVar 2 | from pydantic import BaseModel, RootModel 3 | 4 | 5 | class A(BaseModel): 6 | __root__ = 'xyz' 7 | 8 | 9 | class B(BaseModel): 10 | a = 'xyz' 11 | 12 | class C: 13 | __root__ = 'xyz' 14 | e = 'xyz' 15 | 16 | def d(): 17 | __root__ = 'xyz' 18 | g = 'xyz' 19 | 20 | 21 | class A(RootModel): 22 | root = 'xyz' 23 | 24 | 25 | class B(RootModel): 26 | a = 'xyz' 27 | 28 | 29 | class C(RootModel): 30 | root = 'xyz' 31 | b = 'xyz' 32 | 33 | 34 | class D(RootModel): 35 | root = 'xyz' 36 | _c = 'xyz' 37 | __c = 'xyz' 38 | 39 | class E: 40 | root = 'xyz' 41 | e = 'xyz' 42 | 43 | def f(): 44 | root = 'xyz' 45 | g = 'xyz' 46 | 47 | class G(RootModel): 48 | ATTRIBUTE_NAME: ClassVar[str] = "testing" 49 | root = 'xyz' 50 | 51 | class H(RootModel): 52 | root = 'xyz' 53 | b: str 54 | 55 | class I(RootModel): 56 | b: str 57 | 58 | -------------------------------------------------------------------------------- /docs/ignore-init-arguments.md: -------------------------------------------------------------------------------- 1 | # Ignore `__init__` method arguments 2 | 3 | 4 | !!! info 5 | **This feature is in version 0.3.4 or later** 6 | 7 | You can write `__init__` method on a model for adding some logic. 8 | 9 | However, default arguments on `__init__` method will be overridden, And you will lose autocompletion for `__init__` methods by the plugin. 10 | 11 | ![options_init](init_arguments.png) 12 | 13 | `ignore-init-method-arguments` option resolves this problem. 14 | The option ignore arguments on `__init__` method. 15 | 16 | ![options_ignore_init](ignore_init_arguments.png) 17 | 18 | 19 | The option has to be defined in pyproject.toml 20 | 21 | ```toml 22 | [tool.pydantic-pycharm-plugin] 23 | ignore-init-method-arguments = true 24 | ``` 25 | 26 | !!! info 27 | **This feature is in version 0.4.9 or later** 28 | 29 | If a third-party library provides a model that extends BaseModel, it may override the `__init__` method, as in `__init__(self, **kwargs)`. 30 | If this is the case, the plugin user should set `ignore-init-method-arguments = true` to ignore the `__init__` method argument. 31 | But it is difficult to tell if the library is using BaseModel or not. 32 | 33 | The plugin ignore the `__init__` method if argument is only `**kwargs`. the option is provided as `ignore-init-method-keyword-arguments`. 34 | This option is enabled by default, so if you create a model that inherits from BaseModel with a method like `__init__(self, **kwargs)` defined, ignore this `init` argument. 35 | 36 | If you want to disable this option, please put the following setting in `pyproject.toml`. 37 | 38 | ```toml 39 | [tool.pydantic-pycharm-plugin]. 40 | ignore-init-method-keyword-arguments = true 41 | ``` -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticInsertArgumentsQuickFixTest.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.openapi.command.WriteCommandAction 4 | 5 | class PydanticInsertArgumentsQuickFixTest : PydanticTestCase() { 6 | private fun checkResultByFile() { 7 | myFixture!!.checkResultByFile("${testDataMethodPath}_after.py") 8 | 9 | } 10 | 11 | private fun doTest(onlyRequired: Boolean) { 12 | configureByFile() 13 | val quickFix = PydanticInsertArgumentsQuickFix(onlyRequired) 14 | WriteCommandAction.runWriteCommandAction(myFixture!!.project) { 15 | quickFix.invoke(myFixture!!.project, myFixture!!.editor, myFixture!!.file) 16 | } 17 | checkResultByFile() 18 | } 19 | 20 | fun testNoArguments() { 21 | doTest(false) 22 | } 23 | 24 | // TODO: InsertArgumentsQuickFix for required fields not working properly in PyCharm 2025.2 25 | fun _disabled_testNoArgumentsOnlyRequired() { 26 | doTest(true) 27 | } 28 | 29 | fun testPartArguments() { 30 | doTest(false) 31 | } 32 | 33 | fun testNestedPartArguments() { 34 | doTest(false) 35 | } 36 | 37 | fun testNestedOtherObject() { 38 | doTest(false) 39 | } 40 | 41 | // TODO: Partial arguments quick fix broken in PyCharm 2025.2 42 | fun _disabled_testPartArgumentsOnlyRequired() { 43 | doTest(true) 44 | } 45 | 46 | fun testLastChar() { 47 | doTest(false) 48 | } 49 | 50 | // TODO: Last character quick fix broken in PyCharm 2025.2 51 | fun _disabled_testLastCharOnlyRequired() { 52 | doTest(true) 53 | } 54 | 55 | fun testDataclass() { 56 | doTest(false) 57 | } 58 | } -------------------------------------------------------------------------------- /testData/inspectionv2/readOnlyPropertyFrozenConfigDict.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, ConfigDict 2 | 3 | 4 | class A(BaseModel): 5 | abc: str = '123' 6 | A.abc = '456' 7 | A().abc = '456' 8 | 9 | class B(BaseModel): 10 | abc: str = '123' 11 | model_config = ConfigDict(frozen=True) 12 | 13 | B.abc = '456' 14 | B().abc = '456' 15 | 16 | class C(BaseModel): 17 | abc: str = '123' 18 | model_config = ConfigDict(frozen=False) 19 | C.abc = '456' 20 | C().abc = '456' 21 | 22 | class D(BaseModel): 23 | model_config = ConfigDict(frozen=True) 24 | D.abc = '456' 25 | D().abc = '456' 26 | 27 | frozen = False 28 | class E(BaseModel): 29 | model_config = ConfigDict(frozen=frozen) 30 | E.abc = '456' 31 | E().abc = '456' 32 | 33 | 34 | class F(D): 35 | model_config = ConfigDict(frozen=True) 36 | F.abc = '456' 37 | F().abc = '456' 38 | 39 | 40 | class G(BaseModel): 41 | model_config = ConfigDict(frozen=False) 42 | G.abc = 43 | G.abc = "test" 44 | G.abc.lower() 45 | G.abc.lower() = 'efg' 46 | 47 | 48 | class H: 49 | model_config = ConfigDict(frozen=True) 50 | H.abc = '123' 51 | 52 | config_dict = ConfigDict(frozen=True) 53 | class I(BaseModel): 54 | model_config = config_dict 55 | I.abc = '456' 56 | I().abc = '456' 57 | 58 | class J(BaseModel): 59 | model_config = {'frozen': True} 60 | J.abc = '456' 61 | J().abc = '456' 62 | -------------------------------------------------------------------------------- /testData/inspectionv2/validatorField.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, field_validator, model_validator 2 | 3 | def check(func): 4 | def inner(): 5 | func() 6 | return inner 7 | 8 | FALSE = False 9 | 10 | TRUE = True 11 | 12 | def get_check_fields(): 13 | pass 14 | class A(BaseModel): 15 | a: str 16 | b: str 17 | c: str 18 | d: str 19 | e: str 20 | 21 | @field_validator('a') 22 | def validate_a(cls): 23 | pass 24 | 25 | @field_validator('x') 26 | def validate_b(cls): 27 | pass 28 | 29 | @field_validator('x', check_fields=True) 30 | def validate_a(cls): 31 | pass 32 | @field_validator('x', check_fields=False) 33 | def validate_a(cls): 34 | pass 35 | 36 | @field_validator('x', check_fields=FALSE) 37 | def validate_a(cls): 38 | pass 39 | 40 | @field_validator('x', check_fields=TRUE) 41 | def validate_a(cls): 42 | pass 43 | @field_validator('x', check_fields=get_check_fields()) 44 | def validate_a(cls): 45 | pass 46 | @field_validator('c') 47 | def validate_b(*args): 48 | pass 49 | 50 | @field_validator('d') 51 | def validate_c(**kwargs): 52 | pass 53 | 54 | @field_validator('*') 55 | def validate_c(**kwargs): 56 | pass 57 | 58 | @model_validator(mode='before') 59 | def validate_model_before(cls): 60 | pass 61 | 62 | @model_validator(mode='after') 63 | def validate_model_after(self): 64 | pass 65 | 66 | @model_validator() 67 | def validate_model(cls): 68 | pass 69 | 70 | def dummy(self): 71 | pass 72 | 73 | @check 74 | def task(self): 75 | pass -------------------------------------------------------------------------------- /.github/workflows/run-ui-tests.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow for launching UI tests on Linux, Windows, and Mac in the following steps: 2 | # - prepare and launch IDE with your plugin and robot-server plugin, which is needed to interact with UI 3 | # - wait for IDE to start 4 | # - run UI tests with separate Gradle task 5 | # 6 | # Please check https://github.com/JetBrains/intellij-ui-test-robot for information about UI tests with IntelliJ Platform 7 | # 8 | # Workflow is triggered manually. 9 | 10 | name: Run UI Tests 11 | on: 12 | workflow_dispatch 13 | 14 | jobs: 15 | 16 | testUI: 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - os: ubuntu-latest 23 | runIde: | 24 | export DISPLAY=:99.0 25 | Xvfb -ac :99 -screen 0 1920x1080x16 & 26 | gradle runIdeForUiTests & 27 | - os: windows-latest 28 | runIde: start gradlew.bat runIdeForUiTests 29 | - os: macos-latest 30 | runIde: ./gradlew runIdeForUiTests & 31 | 32 | steps: 33 | 34 | # Check out current repository 35 | - name: Fetch Sources 36 | uses: actions/checkout@v4 37 | 38 | # Setup Java 17 environment for the next steps 39 | - name: Setup Java 40 | uses: actions/setup-java@v4 41 | with: 42 | distribution: zulu 43 | java-version: 17 44 | 45 | # Run IDEA prepared for UI testing 46 | - name: Run IDE 47 | run: ${{ matrix.runIde }} 48 | 49 | # Wait for IDEA to be started 50 | - name: Health Check 51 | uses: jtalk/url-health-check-action@v4 52 | with: 53 | url: http://127.0.0.1:8082 54 | max-attempts: 15 55 | retry-delay: 30s 56 | 57 | # Run tests 58 | - name: Tests 59 | run: ./gradlew test 60 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticConfigService.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.codeInspection.ProblemHighlightType 4 | import com.intellij.openapi.components.PersistentStateComponent 5 | import com.intellij.openapi.components.State 6 | import com.intellij.openapi.components.Storage 7 | import com.intellij.openapi.project.Project 8 | import com.intellij.util.xmlb.XmlSerializerUtil 9 | 10 | @State(name = "PydanticConfigService", storages = [Storage("pydantic.xml")]) 11 | class PydanticConfigService : PersistentStateComponent { 12 | var initTyped = true 13 | var warnUntypedFields = false 14 | var mypyInitTyped: Boolean? = null 15 | var mypyWarnUntypedFields: Boolean? = null 16 | var pyprojectToml: String? = null 17 | var mypyIni: String? = null 18 | var parsableTypeMap = mapOf>() 19 | var parsableTypeHighlightType: ProblemHighlightType = ProblemHighlightType.WARNING 20 | var acceptableTypeMap = mapOf>() 21 | var acceptableTypeHighlightType: ProblemHighlightType = ProblemHighlightType.WEAK_WARNING 22 | var ignoreInitMethodArguments: Boolean = false 23 | var ignoreInitMethodKeywordArguments: Boolean = true 24 | val currentInitTyped: Boolean 25 | get() = this.mypyInitTyped ?: this.initTyped 26 | val currentWarnUntypedFields: Boolean 27 | get() = this.mypyWarnUntypedFields ?: this.warnUntypedFields 28 | 29 | override fun getState(): PydanticConfigService { 30 | return this 31 | } 32 | 33 | override fun loadState(config: PydanticConfigService) { 34 | XmlSerializerUtil.copyBean(config, this) 35 | } 36 | 37 | companion object { 38 | fun getInstance(project: Project): PydanticConfigService { 39 | return project.getService(PydanticConfigService::class.java) 40 | } 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /testSrc/com/koxudaxi/pydantic/PydanticPythonPackageManagementListenerTest.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.openapi.application.invokeLater 4 | import com.jetbrains.python.psi.types.TypeEvalContext 5 | import com.jetbrains.python.sdk.PythonSdkUtil 6 | 7 | 8 | open class PydanticPythonPackageManagementListenerTest : PydanticTestCase() { 9 | // fun testDeleteStubFile() { 10 | // val sdk = PythonSdkUtil.findPythonSdk(myFixture!!.module)!! 11 | // val skeleton = PythonSdkUtil.findSkeletonsDir(sdk)!! 12 | // var pydanticStubDir: VirtualFile? = null 13 | // runWriteAction { 14 | // pydanticStubDir = skeleton.createChildDirectory(null, "pydantic") 15 | // assertTrue(pydanticStubDir!!.exists()) 16 | // } 17 | // PydanticPackageManagerListener().packagesRefreshed(sdk) 18 | // invokeLater { 19 | // assertFalse(pydanticStubDir!!.exists()) 20 | // } 21 | // } 22 | 23 | fun testClearVersion() { 24 | val project = myFixture!!.project 25 | val context = TypeEvalContext.userInitiated(project, null) 26 | val sdk = PythonSdkUtil.findPythonSdk(myFixture!!.module)!! 27 | 28 | PydanticCacheService.setVersion(project, "1.0.1") 29 | val pydanticVersion = PydanticCacheService.getVersion(project) 30 | assertEquals(KotlinVersion(1, 0, 1), pydanticVersion) 31 | 32 | PydanticPythonPackageManagementListener().packagesChanged(sdk) 33 | 34 | invokeLater { 35 | val privateVersionField = PydanticCacheService::class.java.getDeclaredField("version") 36 | privateVersionField.trySetAccessible() 37 | val pydanticVersionService = project.getService(PydanticCacheService::class.java) 38 | val actual = privateVersionField.get(pydanticVersionService) 39 | assertNull(actual) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/koxudaxi/pydantic/PydanticRegexInjector.kt: -------------------------------------------------------------------------------- 1 | package com.koxudaxi.pydantic 2 | 3 | import com.intellij.lang.Language 4 | import com.intellij.lang.injection.MultiHostRegistrar 5 | import com.intellij.openapi.util.TextRange 6 | import com.intellij.psi.PsiElement 7 | import com.intellij.psi.PsiLanguageInjectionHost 8 | import com.jetbrains.python.codeInsight.PyInjectionUtil 9 | import com.jetbrains.python.codeInsight.PyInjectorBase 10 | import com.jetbrains.python.codeInsight.regexp.PythonRegexpLanguage 11 | import com.jetbrains.python.psi.PyFile 12 | import com.jetbrains.python.psi.StringLiteralExpression 13 | 14 | class PydanticRegexInjector : PyInjectorBase() { 15 | override fun registerInjection( 16 | registrar: MultiHostRegistrar, 17 | context: PsiElement, 18 | ): PyInjectionUtil.InjectionResult { 19 | val result = super.registerInjection(registrar, context) 20 | return if (result === PyInjectionUtil.InjectionResult.EMPTY && 21 | context is PsiLanguageInjectionHost && 22 | context.getContainingFile() is PyFile && 23 | context is StringLiteralExpression && isPydanticRegex(context) 24 | ) { 25 | return registerPyElementInjection(registrar, context) 26 | } else result 27 | 28 | } 29 | 30 | override fun getInjectedLanguage(context: PsiElement): Language? { 31 | return null 32 | } 33 | 34 | companion object { 35 | private fun registerPyElementInjection( 36 | registrar: MultiHostRegistrar, 37 | host: PsiLanguageInjectionHost, 38 | ): PyInjectionUtil.InjectionResult { 39 | val text = host.text 40 | registrar.startInjecting(PythonRegexpLanguage.INSTANCE) 41 | registrar.addPlace("", "", host, TextRange(0, text.length)) 42 | registrar.doneInjecting() 43 | return PyInjectionUtil.InjectionResult(true, true) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /testData/mock/pydanticv18/dataclasses.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Type, TypeVar, Union, overload 2 | 3 | if TYPE_CHECKING: 4 | from .main import BaseConfig, BaseModel # noqa: F401 5 | 6 | DataclassT = TypeVar('DataclassT', bound='Dataclass') 7 | 8 | class Dataclass: 9 | __pydantic_model__: Type[BaseModel] 10 | __initialised__: bool 11 | __post_init_original__: Optional[Callable[..., None]] 12 | 13 | def __init__(self, *args: Any, **kwargs: Any) -> None: 14 | pass 15 | 16 | def __call__(self: 'DataclassT', *args: Any, **kwargs: Any) -> 'DataclassT': 17 | pass 18 | 19 | 20 | @overload 21 | def dataclass( 22 | *, 23 | init: bool = True, 24 | repr: bool = True, 25 | eq: bool = True, 26 | order: bool = False, 27 | unsafe_hash: bool = False, 28 | frozen: bool = False, 29 | config: Type[Any] = None, 30 | ) -> Callable[[Type[Any]], Type['Dataclass']]: 31 | ... 32 | 33 | 34 | @overload 35 | def dataclass( 36 | _cls: Type[Any], 37 | *, 38 | init: bool = True, 39 | repr: bool = True, 40 | eq: bool = True, 41 | order: bool = False, 42 | unsafe_hash: bool = False, 43 | frozen: bool = False, 44 | config: Type[Any] = None, 45 | ) -> Type['Dataclass']: 46 | ... 47 | 48 | 49 | def dataclass( 50 | _cls: Optional[Type[Any]] = None, 51 | *, 52 | init: bool = True, 53 | repr: bool = True, 54 | eq: bool = True, 55 | order: bool = False, 56 | unsafe_hash: bool = False, 57 | frozen: bool = False, 58 | config: Type[Any] = None, 59 | ) -> Union[Callable[[Type[Any]], Type['Dataclass']], Type['Dataclass']]: 60 | 61 | def wrap(cls: Type[Any]) -> Type['Dataclass']: 62 | pass 63 | if _cls is None: 64 | return wrap 65 | 66 | return wrap(_cls) 67 | -------------------------------------------------------------------------------- /testData/inspection/rootValidatorSelf.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, root_validator 2 | 3 | def check(func): 4 | def inner(): 5 | func() 6 | return inner 7 | 8 | class A(BaseModel): 9 | a: str 10 | b: str 11 | c: str 12 | d: str 13 | e: str 14 | 15 | @root_validator('a') 16 | def validate_a(self): 17 | pass 18 | 19 | @root_validator('b') 20 | def validate_b(fles): 21 | pass 22 | 23 | @root_validator('c') 24 | def validate_b(*args): 25 | pass 26 | 27 | @root_validator('d') 28 | def validate_c(**kwargs): 29 | pass 30 | 31 | @root_validator('e') 32 | def validate_e(): 33 | pass 34 | 35 | def dummy(self): 36 | pass 37 | 38 | @check 39 | def task(self): 40 | pass 41 | 42 | from pydantic.class_validators import root_validator 43 | 44 | class B(BaseModel): 45 | a: str 46 | b: str 47 | c: str 48 | d: str 49 | e: str 50 | 51 | @root_validator('a') 52 | def validate_a(self): 53 | pass 54 | 55 | @root_validator('b') 56 | def validate_b(fles): 57 | pass 58 | 59 | @root_validator('c') 60 | def validate_b(*args): 61 | pass 62 | 63 | @root_validator('d') 64 | def validate_c(**kwargs): 65 | pass 66 | 67 | @root_validator('e') 68 | def validate_e(): 69 | pass 70 | 71 | def dummy(self): 72 | pass 73 | 74 | @check 75 | def task(self): 76 | pass --------------------------------------------------------------------------------