From 9aae4e7d5a3a4925d394e95c3df7bedcac59d359 Mon Sep 17 00:00:00 2001 From: detachhead Date: Thu, 14 Nov 2024 23:03:20 +1000 Subject: [PATCH] create a separate diagnostic rule for `reportExplicitAny` for backwards compatibility --- .../new-diagnostic-rules.md | 16 +++++++++++++++- docs/configuration.md | 4 +++- .../src/common/configOptions.ts | 8 ++++++++ .../src/common/diagnosticRules.ts | 1 + .../src/tests/reportAny.test.ts | 18 ++++++++++++++---- packages/vscode-pyright/package.json | 19 ++++++++++++++++++- .../schemas/pyrightconfig.schema.json | 13 ++++++++++++- 7 files changed, 71 insertions(+), 8 deletions(-) diff --git a/docs/benefits-over-pyright/new-diagnostic-rules.md b/docs/benefits-over-pyright/new-diagnostic-rules.md index 806d3ec6f..e5c1c6938 100644 --- a/docs/benefits-over-pyright/new-diagnostic-rules.md +++ b/docs/benefits-over-pyright/new-diagnostic-rules.md @@ -35,7 +35,21 @@ def foo(bar, baz: Any) -> Any: print(baz) # no error ``` -basedpyright introduces the `reportAny` option, which will report an error on usages of anything typed as `Any`. +basedpyright introduces the `reportAny` option, which will report an error on usages of anything typed as `Any`: + +```py +def foo(baz: Any) -> Any: + print(baz) # error: reportAny +``` + +## `reportExplicitAny` + +similar to [`reportAny`](#reportany), however this rule bans usages of the `Any` type itself rather than expressions that are typed as `Any`: + +```py +def foo(baz: Any) -> Any: # error: reportExplicitAny + print(baz) # error: reportAny +``` ## `reportIgnoreCommentWithoutRule` diff --git a/docs/configuration.md b/docs/configuration.md index cb65b14d7..e38eb3156 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -269,7 +269,9 @@ the following additional options are not available in regular pyright: - **reportUnreachable** [boolean or string, optional]: Generate or suppress diagnostics for unreachable code. -- **reportAny** [boolean or string, optional]: Ban all usages of the `Any` type. this accounts for all scenarios not covered by the `reportUnknown*` rules (since "Unknown" isn't a real type, but a distinction pyright makes to disallow the `Any` type only in certain circumstances). +- **reportAny** [boolean or string, optional]: Generate or suppress diagnostics for expressions that have the `Any` type. this accounts for all scenarios not covered by the `reportUnknown*` rules (since "Unknown" isn't a real type, but a distinction pyright makes to disallow the `Any` type only in certain circumstances). + +- **reportExplicitAny** [boolean or string, optional]: Ban all explicit usages of the `Any` type. While `reportAny` bans expressions typed as `Any`, this rule bans using the `Any` type directly eg. in a type annotation. - **reportIgnoreCommentWithoutRule** [boolean or string, optional]: Enforce that all `# type:ignore`/`# pyright:ignore` comments specify a rule in brackets (eg. `# pyright:ignore[reportAny]`) diff --git a/packages/pyright-internal/src/common/configOptions.ts b/packages/pyright-internal/src/common/configOptions.ts index 67b6f24dd..4a3e8ccac 100644 --- a/packages/pyright-internal/src/common/configOptions.ts +++ b/packages/pyright-internal/src/common/configOptions.ts @@ -413,6 +413,7 @@ export interface DiagnosticRuleSet { failOnWarnings: boolean; reportUnreachable: DiagnosticLevel; reportAny: DiagnosticLevel; + reportExplicitAny: DiagnosticLevel; reportIgnoreCommentWithoutRule: DiagnosticLevel; reportPrivateLocalImportUsage: DiagnosticLevel; reportImplicitRelativeImport: DiagnosticLevel; @@ -540,6 +541,7 @@ export function getDiagLevelDiagnosticRules() { DiagnosticRule.reportImplicitOverride, DiagnosticRule.reportUnreachable, DiagnosticRule.reportAny, + DiagnosticRule.reportExplicitAny, DiagnosticRule.reportIgnoreCommentWithoutRule, DiagnosticRule.reportInvalidCast, DiagnosticRule.reportImplicitRelativeImport, @@ -673,6 +675,7 @@ export function getOffDiagnosticRuleSet(): DiagnosticRuleSet { failOnWarnings: false, reportUnreachable: 'hint', reportAny: 'none', + reportExplicitAny: 'none', reportIgnoreCommentWithoutRule: 'none', reportPrivateLocalImportUsage: 'none', reportImplicitRelativeImport: 'none', @@ -787,6 +790,7 @@ export function getBasicDiagnosticRuleSet(): DiagnosticRuleSet { failOnWarnings: false, reportUnreachable: 'hint', reportAny: 'none', + reportExplicitAny: 'none', reportIgnoreCommentWithoutRule: 'none', reportPrivateLocalImportUsage: 'none', reportImplicitRelativeImport: 'none', @@ -901,6 +905,7 @@ export function getStandardDiagnosticRuleSet(): DiagnosticRuleSet { failOnWarnings: false, reportUnreachable: 'hint', reportAny: 'none', + reportExplicitAny: 'none', reportIgnoreCommentWithoutRule: 'none', reportPrivateLocalImportUsage: 'none', reportImplicitRelativeImport: 'none', @@ -1014,6 +1019,7 @@ export const getRecommendedDiagnosticRuleSet = (): DiagnosticRuleSet => ({ failOnWarnings: true, reportUnreachable: 'warning', reportAny: 'warning', + reportExplicitAny: 'warning', reportIgnoreCommentWithoutRule: 'warning', reportPrivateLocalImportUsage: 'warning', reportImplicitRelativeImport: 'error', @@ -1124,6 +1130,7 @@ export const getAllDiagnosticRuleSet = (): DiagnosticRuleSet => ({ failOnWarnings: true, reportUnreachable: 'error', reportAny: 'error', + reportExplicitAny: 'error', reportIgnoreCommentWithoutRule: 'error', reportPrivateLocalImportUsage: 'error', reportImplicitRelativeImport: 'error', @@ -1235,6 +1242,7 @@ export function getStrictDiagnosticRuleSet(): DiagnosticRuleSet { failOnWarnings: false, reportUnreachable: 'hint', reportAny: 'none', + reportExplicitAny: 'none', reportIgnoreCommentWithoutRule: 'none', reportPrivateLocalImportUsage: 'none', reportImplicitRelativeImport: 'none', diff --git a/packages/pyright-internal/src/common/diagnosticRules.ts b/packages/pyright-internal/src/common/diagnosticRules.ts index 27e2d766d..332f799ab 100644 --- a/packages/pyright-internal/src/common/diagnosticRules.ts +++ b/packages/pyright-internal/src/common/diagnosticRules.ts @@ -108,6 +108,7 @@ export enum DiagnosticRule { failOnWarnings = 'failOnWarnings', reportUnreachable = 'reportUnreachable', reportAny = 'reportAny', + reportExplicitAny = 'reportExplicitAny', reportIgnoreCommentWithoutRule = 'reportIgnoreCommentWithoutRule', reportPrivateLocalImportUsage = 'reportPrivateLocalImportUsage', reportImplicitRelativeImport = 'reportImplicitRelativeImport', diff --git a/packages/pyright-internal/src/tests/reportAny.test.ts b/packages/pyright-internal/src/tests/reportAny.test.ts index dc8480942..817f15821 100644 --- a/packages/pyright-internal/src/tests/reportAny.test.ts +++ b/packages/pyright-internal/src/tests/reportAny.test.ts @@ -12,8 +12,6 @@ test('reportAny', () => { validateResultsButBased(analysisResults, { errors: [ { line: 3, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, - { line: 3, code: DiagnosticRule.reportAny, message: LocMessage.explicitAny() }, - { line: 3, code: DiagnosticRule.reportAny, message: LocMessage.explicitAny() }, { line: 3, code: DiagnosticRule.reportAny, @@ -22,7 +20,6 @@ test('reportAny', () => { { line: 4, code: DiagnosticRule.reportAny }, { line: 5, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, { line: 7, code: DiagnosticRule.reportAny, message: LocMessage.typeAny().format({ name: 'bar' }) }, - { line: 7, code: DiagnosticRule.reportAny, message: LocMessage.explicitAny() }, { line: 9, code: DiagnosticRule.reportAny, @@ -43,7 +40,6 @@ test('reportAny', () => { code: DiagnosticRule.reportAny, message: LocMessage.lambdaReturnTypeAny(), }, - { line: 15, code: DiagnosticRule.reportAny, message: LocMessage.explicitAny() }, { line: 18, code: DiagnosticRule.reportAny, @@ -52,3 +48,17 @@ test('reportAny', () => { ], }); }); + +test('reportExplicitAny', () => { + const configOptions = new ConfigOptions(Uri.empty()); + configOptions.diagnosticRuleSet.reportExplicitAny = 'error'; + const analysisResults = typeAnalyzeSampleFiles(['reportAny.py'], configOptions); + + validateResultsButBased(analysisResults, { + errors: [3, 3, 7, 15].map((lineNumber) => ({ + line: lineNumber, + code: DiagnosticRule.reportAny, + message: LocMessage.explicitAny(), + })), + }); +}); diff --git a/packages/vscode-pyright/package.json b/packages/vscode-pyright/package.json index d5be14598..134c01b87 100644 --- a/packages/vscode-pyright/package.json +++ b/packages/vscode-pyright/package.json @@ -1596,7 +1596,24 @@ "string", "boolean" ], - "description": "Diagnostics for anything with the `Any` type", + "description": "Diagnostics for expressions with the `Any` type", + "default": "none", + "enum": [ + "none", + "hint", + "information", + "warning", + "error", + true, + false + ] + }, + "reportExplicitAny": { + "type": [ + "string", + "boolean" + ], + "description": "Diagnostics for type annotations that use the `Any` type", "default": "none", "enum": [ "none", diff --git a/packages/vscode-pyright/schemas/pyrightconfig.schema.json b/packages/vscode-pyright/schemas/pyrightconfig.schema.json index 93f473690..29c00344c 100644 --- a/packages/vscode-pyright/schemas/pyrightconfig.schema.json +++ b/packages/vscode-pyright/schemas/pyrightconfig.schema.json @@ -512,7 +512,12 @@ }, "reportAny": { "$ref": "#/definitions/diagnostic", - "title": "Controls reporting of values typed as `Any`", + "title": "Controls reporting of expressions typed as `Any`", + "default": "none" + }, + "reportExplicitAny": { + "$ref": "#/definitions/diagnostic", + "title": "Controls reporting of type annotations that use the `Any` type", "default": "none" }, "reportIgnoreCommentWithoutRule": { @@ -920,6 +925,9 @@ "reportAny": { "$ref": "#/definitions/reportAny" }, + "reportExplicitAny": { + "$ref": "#/definitions/reportExplicitAny" + }, "reportIgnoreCommentWithoutRule": { "$ref": "#/definitions/reportIgnoreCommentWithoutRule" }, @@ -1268,6 +1276,9 @@ "reportAny": { "$ref": "#/definitions/reportAny" }, + "reportExplicitAny": { + "$ref": "#/definitions/reportExplicitAny" + }, "reportIgnoreCommentWithoutRule": { "$ref": "#/definitions/reportIgnoreCommentWithoutRule" },