mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-26 10:55:06 +03:00
Added new diagnostic check "reportMissingParameterType" that checks for function and method input parameters that are missing a type annotation.
This commit is contained in:
parent
ca2c251fff
commit
ff55b895f9
@ -126,6 +126,8 @@ The following settings control pyright’s diagnostic output (warnings or errors
|
||||
|
||||
**reportUnknownMemberType** [boolean or string, optional]: Generate or suppress diagnostics for class or instance variables that have an unknown type. The default value for this setting is 'none'.
|
||||
|
||||
**reportMissingParameterType** [boolean or string, optional]: Generate or suppress diagnostics for input parameters for functions or methods that are missing a type annotation. The 'self' and 'cls' parameters used within methods are exempt from this check. The default value for this setting is 'none'.
|
||||
|
||||
**reportMissingTypeArgument** [boolean or string, optional]: Generate or suppress diagnostics when a generic class is used without providing explicit or implicit type arguments. The default value for this setting is 'none'.
|
||||
|
||||
**reportInvalidTypeVarUse** [boolean or string, optional]: Generate or suppress diagnostics when a TypeVar is used inappropriately (e.g. if a TypeVar appears only once) within a generic function signature. The default value for this setting is 'none'.
|
||||
@ -308,6 +310,7 @@ The following table lists the default severity levels for each diagnostic rule w
|
||||
| reportUnknownLambdaType | "none" | "none" | "error" |
|
||||
| reportUnknownVariableType | "none" | "none" | "error" |
|
||||
| reportUnknownMemberType | "none" | "none" | "error" |
|
||||
| reportMissingParameterType | "none" | "none" | "error" |
|
||||
| reportMissingTypeArgument | "none" | "none" | "error" |
|
||||
| reportInvalidTypeVarUse | "none" | "warning" | "error" |
|
||||
| reportCallInDefaultInitializer | "none" | "none" | "none" |
|
||||
|
@ -340,7 +340,7 @@ export class Checker extends ParseTreeWalker {
|
||||
// parameters after this need to be flagged as an error.
|
||||
let sawParamSpecArgs = false;
|
||||
|
||||
// Report any unknown parameter types.
|
||||
// Report any unknown or missing parameter types.
|
||||
node.parameters.forEach((param, index) => {
|
||||
if (param.name) {
|
||||
// Determine whether this is a P.args parameter.
|
||||
@ -370,7 +370,7 @@ export class Checker extends ParseTreeWalker {
|
||||
);
|
||||
}
|
||||
|
||||
// Allow unknown param types if the param is named '_'.
|
||||
// Allow unknown and missing param types if the param is named '_'.
|
||||
if (param.name && param.name.value !== '_') {
|
||||
if (index < functionTypeResult.functionType.details.parameters.length) {
|
||||
const paramType = functionTypeResult.functionType.details.parameters[index].type;
|
||||
@ -403,6 +403,26 @@ export class Checker extends ParseTreeWalker {
|
||||
param.name
|
||||
);
|
||||
}
|
||||
|
||||
let hasAnnotation = false;
|
||||
|
||||
if (functionTypeResult.functionType.details.parameters[index].typeAnnotation) {
|
||||
hasAnnotation = true;
|
||||
} else {
|
||||
// See if this is a "self" and "cls" parameter. They are exempt from this rule.
|
||||
if (isTypeVar(paramType) && paramType.details.isSynthesizedSelfCls) {
|
||||
hasAnnotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAnnotation) {
|
||||
this._evaluator.addDiagnostic(
|
||||
this._fileInfo.diagnosticRuleSet.reportMissingParameterType,
|
||||
DiagnosticRule.reportMissingParameterType,
|
||||
Localizer.Diagnostic.paramAnnotationMissing().format({ name: param.name.value }),
|
||||
param.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +214,9 @@ export interface DiagnosticRuleSet {
|
||||
// Report usage of unknown input or return parameters?
|
||||
reportUnknownMemberType: DiagnosticLevel;
|
||||
|
||||
// Report input parameters that are missing type annotations?
|
||||
reportMissingParameterType: DiagnosticLevel;
|
||||
|
||||
// Report usage of generic class without explicit type arguments?
|
||||
reportMissingTypeArgument: DiagnosticLevel;
|
||||
|
||||
@ -328,6 +331,7 @@ export function getDiagLevelDiagnosticRules() {
|
||||
DiagnosticRule.reportUnknownLambdaType,
|
||||
DiagnosticRule.reportUnknownVariableType,
|
||||
DiagnosticRule.reportUnknownMemberType,
|
||||
DiagnosticRule.reportMissingParameterType,
|
||||
DiagnosticRule.reportMissingTypeArgument,
|
||||
DiagnosticRule.reportInvalidTypeVarUse,
|
||||
DiagnosticRule.reportCallInDefaultInitializer,
|
||||
@ -402,6 +406,7 @@ export function getOffDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUnknownLambdaType: 'none',
|
||||
reportUnknownVariableType: 'none',
|
||||
reportUnknownMemberType: 'none',
|
||||
reportMissingParameterType: 'none',
|
||||
reportMissingTypeArgument: 'none',
|
||||
reportInvalidTypeVarUse: 'none',
|
||||
reportCallInDefaultInitializer: 'none',
|
||||
@ -472,6 +477,7 @@ export function getBasicDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUnknownLambdaType: 'none',
|
||||
reportUnknownVariableType: 'none',
|
||||
reportUnknownMemberType: 'none',
|
||||
reportMissingParameterType: 'none',
|
||||
reportMissingTypeArgument: 'none',
|
||||
reportInvalidTypeVarUse: 'warning',
|
||||
reportCallInDefaultInitializer: 'none',
|
||||
@ -542,6 +548,7 @@ export function getStrictDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUnknownLambdaType: 'error',
|
||||
reportUnknownVariableType: 'error',
|
||||
reportUnknownMemberType: 'error',
|
||||
reportMissingParameterType: 'error',
|
||||
reportMissingTypeArgument: 'error',
|
||||
reportInvalidTypeVarUse: 'error',
|
||||
reportCallInDefaultInitializer: 'none',
|
||||
@ -1155,6 +1162,13 @@ export class ConfigOptions {
|
||||
defaultSettings.reportUnknownMemberType
|
||||
),
|
||||
|
||||
// Read the "reportMissingParameterType" entry.
|
||||
reportMissingParameterType: this._convertDiagnosticLevel(
|
||||
configObj.reportMissingParameterType,
|
||||
DiagnosticRule.reportMissingParameterType,
|
||||
defaultSettings.reportMissingParameterType
|
||||
),
|
||||
|
||||
// Read the "reportMissingTypeArgument" entry.
|
||||
reportMissingTypeArgument: this._convertDiagnosticLevel(
|
||||
configObj.reportMissingTypeArgument,
|
||||
|
@ -54,6 +54,7 @@ export enum DiagnosticRule {
|
||||
reportUnknownLambdaType = 'reportUnknownLambdaType',
|
||||
reportUnknownVariableType = 'reportUnknownVariableType',
|
||||
reportUnknownMemberType = 'reportUnknownMemberType',
|
||||
reportMissingParameterType = 'reportMissingParameterType',
|
||||
reportMissingTypeArgument = 'reportMissingTypeArgument',
|
||||
reportInvalidTypeVarUse = 'reportInvalidTypeVarUse',
|
||||
reportCallInDefaultInitializer = 'reportCallInDefaultInitializer',
|
||||
|
@ -550,6 +550,8 @@ export namespace Localizer {
|
||||
export const paramAfterKwargsParam = () => getRawString('Diagnostic.paramAfterKwargsParam');
|
||||
export const paramAlreadyAssigned = () =>
|
||||
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.paramAlreadyAssigned'));
|
||||
export const paramAnnotationMissing = () =>
|
||||
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.paramAnnotationMissing'));
|
||||
export const paramNameMissing = () =>
|
||||
new ParameterizedString<{ name: string }>(getRawString('Diagnostic.paramNameMissing'));
|
||||
export const paramSpecArgsKwargsUsage = () => getRawString('Diagnostic.paramSpecArgsKwargsUsage');
|
||||
|
@ -255,6 +255,7 @@
|
||||
"overloadWithoutImplementation": "\"{name}\" is marked as overload, but no implementation is provided",
|
||||
"paramAfterKwargsParam": "Parameter cannot follow \"**\" parameter",
|
||||
"paramAlreadyAssigned": "Parameter \"{name}\" is already assigned",
|
||||
"paramAnnotationMissing": "Type annotation is missing for parameter \"{name}\"",
|
||||
"paramNameMissing": "No parameter named \"{name}\"",
|
||||
"paramSpecArgsKwargsUsage": "\"args\" and \"kwargs\" members of ParamSpec must both appear within a function signature",
|
||||
"paramSpecArgsUsage": "\"args\" member of ParamSpec is valid only when used with *args parameter",
|
||||
|
@ -1,6 +1,6 @@
|
||||
# This sample tests support for comment-style function annotations.
|
||||
|
||||
# pyright: strict
|
||||
# pyright: strict, reportMissingParameterType=false
|
||||
|
||||
from typing import Optional
|
||||
|
||||
@ -47,6 +47,7 @@ def func1f(a):
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
|
||||
def func1g(*args, **kwargs):
|
||||
# type: (*int, **float) -> int
|
||||
return sum(args) + sum(round(kwarg) for kwarg in kwargs.values())
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
# We use "strict" here because we want to ensure that there are
|
||||
# no "unknown" types remaining in this file.
|
||||
# pyright: strict, reportUnknownParameterType=false
|
||||
# pyright: strict, reportUnknownParameterType=false, reportMissingParameterType=false
|
||||
|
||||
from logging import Handler, NOTSET
|
||||
|
||||
|
12
packages/pyright-internal/src/tests/samples/parameters1.py
Normal file
12
packages/pyright-internal/src/tests/samples/parameters1.py
Normal file
@ -0,0 +1,12 @@
|
||||
# This sample tests the reportMissingParameterType check.
|
||||
|
||||
|
||||
class A:
|
||||
# This should generate an error if reportMissingParameterType is enabled
|
||||
# because 'y' is missing a type annotation.
|
||||
def method1(self, x: int, _, y) -> int:
|
||||
...
|
||||
|
||||
def method2(self, x, y):
|
||||
# type: (int, int) -> int
|
||||
...
|
@ -1006,3 +1006,15 @@ test('Slots2', () => {
|
||||
|
||||
TestUtils.validateResults(analysisResults, 3);
|
||||
});
|
||||
|
||||
test('Parameters1', () => {
|
||||
const configOptions = new ConfigOptions('.');
|
||||
|
||||
configOptions.diagnosticRuleSet.reportMissingParameterType = 'none';
|
||||
const analysisResults1 = TestUtils.typeAnalyzeSampleFiles(['parameters1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults1, 0);
|
||||
|
||||
configOptions.diagnosticRuleSet.reportMissingParameterType = 'error';
|
||||
const analysisResults2 = TestUtils.typeAnalyzeSampleFiles(['parameters1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults2, 1);
|
||||
});
|
||||
|
@ -520,6 +520,17 @@
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportMissingParameterType": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for parameters that are missing a type annotation.",
|
||||
"default": "none",
|
||||
"enum": [
|
||||
"none",
|
||||
"information",
|
||||
"warning",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportMissingTypeArgument": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for generic class reference with missing type arguments.",
|
||||
|
@ -353,6 +353,12 @@
|
||||
"title": "Controls reporting class and instance variables whose types are unknown",
|
||||
"default": "none"
|
||||
},
|
||||
"reportMissingParameterType": {
|
||||
"$id": "#/properties/reportMissingParameterType",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
"title": "Controls reporting input parameters that are missing a type annotation",
|
||||
"default": "none"
|
||||
},
|
||||
"reportMissingTypeArgument": {
|
||||
"$id": "#/properties/reportMissingTypeArgument",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
|
Loading…
Reference in New Issue
Block a user