From bb4adc93a8309b292be8318f0c379b192f537868 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 5 Mar 2025 15:35:01 +0200 Subject: [PATCH 1/5] feat: Support basedpyright linter --- linters/basedpyright/basedpyright.test.ts | 3 + linters/basedpyright/basedpyright_to_sarif.py | 41 ++++ linters/basedpyright/plugin.yaml | 36 +++ linters/basedpyright/test_data/basic.in.py | 57 +++++ .../pyright_v1.28.1_basic.check.shot | 226 ++++++++++++++++++ 5 files changed, 363 insertions(+) create mode 100644 linters/basedpyright/basedpyright.test.ts create mode 100755 linters/basedpyright/basedpyright_to_sarif.py create mode 100644 linters/basedpyright/plugin.yaml create mode 100644 linters/basedpyright/test_data/basic.in.py create mode 100644 linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot diff --git a/linters/basedpyright/basedpyright.test.ts b/linters/basedpyright/basedpyright.test.ts new file mode 100644 index 000000000..67e00e8f9 --- /dev/null +++ b/linters/basedpyright/basedpyright.test.ts @@ -0,0 +1,3 @@ +import { linterCheckTest } from "tests"; + +linterCheckTest({ linterName: "basedpyright" }); diff --git a/linters/basedpyright/basedpyright_to_sarif.py b/linters/basedpyright/basedpyright_to_sarif.py new file mode 100755 index 000000000..5efa2bfaa --- /dev/null +++ b/linters/basedpyright/basedpyright_to_sarif.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import json +import sys + +results = [] + +for result in json.load(sys.stdin)["generalDiagnostics"]: + parse = { + "level": result["severity"] if result["severity"] != "information" else "note", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": result["file"], + }, + "region": { + "startLine": result["range"]["start"]["line"] + + 1, # basedpyright is 0-indexed, SARIF is 1-indexed + "startColumn": result["range"]["start"]["character"] + 1, + "endLine": result["range"]["end"]["line"] + 1, + "endColumn": result["range"]["end"]["character"] + 1, + }, + } + } + ], + "message": { + "text": result["message"].replace("Â", ""), + }, + } + if "rule" in result: + parse["ruleId"] = result["rule"] + results.append(parse) + +sarif = { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [{"results": results}], +} + +print(json.dumps(sarif, indent=2)) diff --git a/linters/basedpyright/plugin.yaml b/linters/basedpyright/plugin.yaml new file mode 100644 index 000000000..aca5eab77 --- /dev/null +++ b/linters/basedpyright/plugin.yaml @@ -0,0 +1,36 @@ +version: 0.1 +tools: + definitions: + - name: basedpyright + runtime: python + package: basedpyright + shims: [basedpyright] + known_good_version: 1.28.1 +lint: + definitions: + - name: basedpyright + files: [python] + suggest_if: config_present + description: Basedpyright is a fork of pyright with various type checking improvements, pylance features and more + commands: + - name: lint + output: sarif + run: basedpyright --outputjson ${target} + success_codes: [0, 1] + read_output_from: stdout + batch: true + cache_results: false + parser: + runtime: python + run: python3 ${plugin}/linters/basedpyright/basedpyright_to_sarif.py + tools: [basedpyright] + direct_configs: + - pyrightconfig.json + affects_cache: + - pyproject.toml + - setup.cfg + issue_url_format: https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#{} + known_good_version: 1.28.1 + version_command: + parse_regex: basedpyright ${semver} + run: basedpyright --version diff --git a/linters/basedpyright/test_data/basic.in.py b/linters/basedpyright/test_data/basic.in.py new file mode 100644 index 000000000..291049af6 --- /dev/null +++ b/linters/basedpyright/test_data/basic.in.py @@ -0,0 +1,57 @@ +from typing import Callable, Iterator, Union, Optional, Enum + + +def wrong_type(x: int) -> str: + return x # error: Incompatible return value type (got "int", expected "str") + +class A: + def method1(self) -> None: + self.x = 1 + + def method2(self) -> None: + self.x = "" # Mypy treats this as an error because `x` is implicitly declared as `int` + +a = A() +reveal_type(a.x) + +a.x = "" # Basedpyright allows this because the type of `x` is `int | str` +a.x = 3.0 # Basedpyright treats this as an error because the type of `x` is `int | str` + + + +class A: + x: int = 0 # Regular class variable + y: ClassVar[int] = 0 # Pure class variable + + def __init__(self): + self.z = 0 # Pure instance variable + +print(A.x) +print(A.y) +print(A.z) # basedpyright shows error, mypy shows no error + + + +class Color(Enum): + RED = 1 + BLUE = 2 + +def is_red(color: Color) -> bool: + if color == Color.RED: + return True + elif color == Color.BLUE: + return False + # mypy reports error: Missing return statement + + +def func(val: int | None): + if val is not None: + + def inner_1() -> None: + reveal_type(val) + print(val + 1) # mypy produces a false positive error here + + inner_2 = lambda: reveal_type(val) + 1 + + inner_1() + inner_2() diff --git a/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot b/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot new file mode 100644 index 000000000..7331e0d33 --- /dev/null +++ b/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot @@ -0,0 +1,226 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP +// trunk-upgrade-validation:RELEASE + +exports[`Testing linter basedpyright test basic 1`] = ` +{ + "issues": [ + { + "code": "reportAttributeAccessIssue", + "column": "57", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "level": "LEVEL_HIGH", + "line": "1", + "linter": "basedpyright", + "message": ""Enum" is unknown import symbol", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "4", + "offset": "56", + }, + ], + "targetType": "python", + }, + { + "column": "13", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "level": "LEVEL_LOW", + "line": "15", + "linter": "basedpyright", + "message": "Type of "a.x" is "int | str"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "384", + }, + ], + "targetType": "python", + }, + { + "code": "reportAttributeAccessIssue", + "column": "3", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "level": "LEVEL_HIGH", + "line": "18", + "linter": "basedpyright", + "message": "Cannot assign to attribute "x" for class "A" +  Expression of type "float" cannot be assigned to attribute "x" of class "A" +    Type "float" is not assignable to type "int | str" +      "float" is not assignable to "int" +      "float" is not assignable to "str"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "462", + }, + ], + "targetType": "python", + }, + { + "code": "reportUndefinedVariable", + "column": "8", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportUndefinedVariable", + "level": "LEVEL_HIGH", + "line": "24", + "linter": "basedpyright", + "message": ""ClassVar" is not defined", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "602", + }, + ], + "targetType": "python", + }, + { + "code": "reportAttributeAccessIssue", + "column": "9", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "level": "LEVEL_HIGH", + "line": "31", + "linter": "basedpyright", + "message": "Cannot access attribute "z" for class "type[A]" +  Attribute "z" is unknown", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "742", + }, + ], + "targetType": "python", + }, + { + "code": "reportReturnType", + "column": "29", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportReturnType", + "level": "LEVEL_HIGH", + "line": "39", + "linter": "basedpyright", + "message": "Function with declared return type "bool" must return value on all code paths +  "None" is not assignable to "bool"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "4", + "offset": "864", + }, + ], + "targetType": "python", + }, + { + "code": "reportReturnType", + "column": "12", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportReturnType", + "level": "LEVEL_HIGH", + "line": "5", + "linter": "basedpyright", + "message": "Type "int" is not assignable to return type "str" +  "int" is not assignable to "str"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "105", + }, + ], + "targetType": "python", + }, + { + "column": "25", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "level": "LEVEL_LOW", + "line": "51", + "linter": "basedpyright", + "message": "Type of "val" is "int"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "1128", + }, + ], + "targetType": "python", + }, + { + "column": "39", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "level": "LEVEL_LOW", + "line": "54", + "linter": "basedpyright", + "message": "Type of "val" is "int"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "1244", + }, + ], + "targetType": "python", + }, + { + "code": "reportRedeclaration", + "column": "7", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportRedeclaration", + "level": "LEVEL_HIGH", + "line": "7", + "linter": "basedpyright", + "message": "Class declaration "A" is obscured by a declaration of the same name", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "183", + }, + ], + "targetType": "python", + }, + ], + "lintActions": [ + { + "command": "lint", + "fileGroupName": "python", + "linter": "basedpyright", + "paths": [ + "test_data/basic.in.py", + ], + "verb": "TRUNK_VERB_CHECK", + }, + { + "command": "lint", + "fileGroupName": "python", + "linter": "basedpyright", + "paths": [ + "test_data/basic.in.py", + ], + "upstream": true, + "verb": "TRUNK_VERB_CHECK", + }, + ], + "taskFailures": [], + "unformattedFiles": [], +} +`; From 0042be1e9dc4b13ee2687bf43b2f4e1e5445b49f Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 5 Mar 2025 15:56:14 +0200 Subject: [PATCH 2/5] test: Update test snapshot for basedpyright --- .../pyright_v1.28.1_basic.check.shot | 430 +++++++++++++++++- 1 file changed, 406 insertions(+), 24 deletions(-) diff --git a/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot b/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot index 7331e0d33..b07b6edf7 100644 --- a/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot +++ b/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot @@ -4,12 +4,145 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "issues": [ + { + "code": "reportUnusedImport", + "column": "20", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnusedImport", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "Import "Callable" is not accessed", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "19", + }, + ], + "targetType": "python", + }, + { + "code": "reportDeprecated", + "column": "30", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportDeprecated", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "This type is deprecated as of Python 3.9; use "collections.abc.Iterator" instead", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "29", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnusedImport", + "column": "30", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnusedImport", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "Import "Iterator" is not accessed", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "29", + }, + ], + "targetType": "python", + }, + { + "code": "reportDeprecated", + "column": "40", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportDeprecated", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "This type is deprecated as of Python 3.10; use "|" instead", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "5", + "offset": "39", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnusedImport", + "column": "40", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnusedImport", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "Import "Union" is not accessed", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "5", + "offset": "39", + }, + ], + "targetType": "python", + }, + { + "code": "reportDeprecated", + "column": "47", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportDeprecated", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "This type is deprecated as of Python 3.10; use "| None" instead", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "46", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnusedImport", + "column": "47", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnusedImport", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "Import "Optional" is not accessed", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "8", + "offset": "46", + }, + ], + "targetType": "python", + }, { "code": "reportAttributeAccessIssue", "column": "57", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportAttributeAccessIssue", "level": "LEVEL_HIGH", "line": "1", "linter": "basedpyright", @@ -23,11 +156,30 @@ exports[`Testing linter basedpyright test basic 1`] = ` ], "targetType": "python", }, + { + "code": "reportUnknownVariableType", + "column": "57", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownVariableType", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "basedpyright", + "message": "Type of "Enum" is unknown", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "4", + "offset": "56", + }, + ], + "targetType": "python", + }, { "column": "13", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#", "level": "LEVEL_LOW", "line": "15", "linter": "basedpyright", @@ -46,20 +198,39 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "3", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportAttributeAccessIssue", "level": "LEVEL_HIGH", "line": "18", "linter": "basedpyright", "message": "Cannot assign to attribute "x" for class "A" -  Expression of type "float" cannot be assigned to attribute "x" of class "A" -    Type "float" is not assignable to type "int | str" -      "float" is not assignable to "int" -      "float" is not assignable to "str"", + Expression of type "float" cannot be assigned to attribute "x" of class "A" + Type "float" is not assignable to type "int | str" + "float" is not assignable to "int" + "float" is not assignable to "str"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "467", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnknownVariableType", + "column": "5", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownVariableType", + "level": "LEVEL_MEDIUM", + "line": "24", + "linter": "basedpyright", + "message": "Type of "y" is unknown", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "462", + "offset": "609", }, ], "targetType": "python", @@ -69,7 +240,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "8", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportUndefinedVariable", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUndefinedVariable", "level": "LEVEL_HIGH", "line": "24", "linter": "basedpyright", @@ -78,7 +249,104 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "8", - "offset": "602", + "offset": "612", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnannotatedClassAttribute", + "column": "14", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnannotatedClassAttribute", + "level": "LEVEL_MEDIUM", + "line": "27", + "linter": "basedpyright", + "message": "Type annotation for attribute `z` is required because this class is not decorated with `@final`", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "690", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnknownArgumentType", + "column": "7", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownArgumentType", + "level": "LEVEL_MEDIUM", + "line": "30", + "linter": "basedpyright", + "message": "Argument type is unknown + Argument corresponds to parameter "values" in function "print"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "739", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnknownMemberType", + "column": "7", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownMemberType", + "level": "LEVEL_MEDIUM", + "line": "30", + "linter": "basedpyright", + "message": "Type of "y" is unknown", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "739", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnknownArgumentType", + "column": "7", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownArgumentType", + "level": "LEVEL_MEDIUM", + "line": "31", + "linter": "basedpyright", + "message": "Argument type is unknown + Argument corresponds to parameter "values" in function "print"", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "750", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnknownMemberType", + "column": "7", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnknownMemberType", + "level": "LEVEL_MEDIUM", + "line": "31", + "linter": "basedpyright", + "message": "Type of "z" is unknown", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "750", }, ], "targetType": "python", @@ -88,17 +356,74 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "9", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportAttributeAccessIssue", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportAttributeAccessIssue", "level": "LEVEL_HIGH", "line": "31", "linter": "basedpyright", "message": "Cannot access attribute "z" for class "type[A]" -  Attribute "z" is unknown", + Attribute "z" is unknown", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "742", + "offset": "752", + }, + ], + "targetType": "python", + }, + { + "code": "reportUntypedBaseClass", + "column": "13", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUntypedBaseClass", + "level": "LEVEL_MEDIUM", + "line": "35", + "linter": "basedpyright", + "message": "Base class type is unknown, obscuring type of derived class", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "4", + "offset": "818", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnannotatedClassAttribute", + "column": "5", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnannotatedClassAttribute", + "level": "LEVEL_MEDIUM", + "line": "36", + "linter": "basedpyright", + "message": "Type annotation for attribute `RED` is required because this class is not decorated with `@final`", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "3", + "offset": "829", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnannotatedClassAttribute", + "column": "5", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnannotatedClassAttribute", + "level": "LEVEL_MEDIUM", + "line": "37", + "linter": "basedpyright", + "message": "Type annotation for attribute `BLUE` is required because this class is not decorated with `@final`", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "4", + "offset": "841", }, ], "targetType": "python", @@ -108,17 +433,17 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "29", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportReturnType", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportReturnType", "level": "LEVEL_HIGH", "line": "39", "linter": "basedpyright", "message": "Function with declared return type "bool" must return value on all code paths -  "None" is not assignable to "bool"", + "None" is not assignable to "bool"", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "4", - "offset": "864", + "offset": "879", }, ], "targetType": "python", @@ -128,12 +453,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "12", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportReturnType", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportReturnType", "level": "LEVEL_HIGH", "line": "5", "linter": "basedpyright", "message": "Type "int" is not assignable to return type "str" -  "int" is not assignable to "str"", + "int" is not assignable to "str"", "ranges": [ { "filePath": "test_data/basic.in.py", @@ -147,7 +472,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "25", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#", "level": "LEVEL_LOW", "line": "51", "linter": "basedpyright", @@ -156,7 +481,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "1128", + "offset": "1143", }, ], "targetType": "python", @@ -165,7 +490,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "39", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#", "level": "LEVEL_LOW", "line": "54", "linter": "basedpyright", @@ -174,7 +499,26 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "1244", + "offset": "1259", + }, + ], + "targetType": "python", + }, + { + "code": "reportUnusedCallResult", + "column": "9", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnusedCallResult", + "level": "LEVEL_MEDIUM", + "line": "57", + "linter": "basedpyright", + "message": "Result of call expression is of type "int" and is not used; assign to variable "_" if this is intentional", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "9", + "offset": "1295", }, ], "targetType": "python", @@ -184,8 +528,8 @@ exports[`Testing linter basedpyright test basic 1`] = ` "column": "7", "file": "test_data/basic.in.py", "issueClass": "ISSUE_CLASS_EXISTING", - "issueUrl": "https://github.com/microsoft/basedpyright/blob/main/docs/configuration.md#reportRedeclaration", - "level": "LEVEL_HIGH", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportRedeclaration", + "level": "LEVEL_MEDIUM", "line": "7", "linter": "basedpyright", "message": "Class declaration "A" is obscured by a declaration of the same name", @@ -198,6 +542,44 @@ exports[`Testing linter basedpyright test basic 1`] = ` ], "targetType": "python", }, + { + "code": "reportUnannotatedClassAttribute", + "column": "14", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUnannotatedClassAttribute", + "level": "LEVEL_MEDIUM", + "line": "9", + "linter": "basedpyright", + "message": "Type annotation for attribute `x` is required because this class is not decorated with `@final`", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "230", + }, + ], + "targetType": "python", + }, + { + "code": "reportUninitializedInstanceVariable", + "column": "14", + "file": "test_data/basic.in.py", + "issueClass": "ISSUE_CLASS_EXISTING", + "issueUrl": "https://github.com/DetachHead/basedpyright/blob/main/docs/configuration/config-files.md#reportUninitializedInstanceVariable", + "level": "LEVEL_HIGH", + "line": "9", + "linter": "basedpyright", + "message": "Instance variable "x" is not initialized in the class body or __init__ method", + "ranges": [ + { + "filePath": "test_data/basic.in.py", + "length": "1", + "offset": "230", + }, + ], + "targetType": "python", + }, ], "lintActions": [ { From 8f60a96b33c1169a3b0f06f0ced37c6222743639 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 5 Mar 2025 16:03:50 +0200 Subject: [PATCH 3/5] chore: Fix README and reformat --- README.md | 107 ++++++++++++++++--------------- linters/basedpyright/plugin.yaml | 4 +- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index d0545e841..b63d5e794 100644 --- a/README.md +++ b/README.md @@ -38,59 +38,59 @@ Enable the following tools via: trunk check enable {linter} ``` -| Technology | Linters | -| --------------- | ------------------------------------------------------------------------------------------------------------------------ | -| All | [codespell], [cspell], [gitleaks], [git-diff-check], [pre-commit-hooks], [trunk-toolbox], [vale] | -| Ansible | [ansible-lint] | -| Apex | [pmd] | -| Bash | [shellcheck], [shfmt] | -| Bazel, Starlark | [buildifier] | -| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | -| C# | [dotnet-format] | -| CircleCI Config | [circleci] | -| Cloudformation | [cfnlint], [checkov] | -| CMake | [cmake-format] | -| CSS, SCSS | [stylelint], [prettier] | -| Cue | [cue-fmt] | -| Dart | [dart] | -| Docker | [hadolint], [checkov] | -| Dotenv | [dotenv-linter] | -| GitHub | [actionlint] | -| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | -| GraphQL | [graphql-schema-linter], [prettier] | -| HAML | [haml-lint] | -| HTML Templates | [djlint] | -| Java | [google-java-format], [pmd], [semgrep] | -| Javascript | [biome], [deno], [eslint], [prettier], [rome], [semgrep] | -| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | -| Kotlin | [detekt], [ktlint] | -| Kubernetes | [kube-linter] | -| Lua | [stylua] | -| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint] | -| Nix | [nixpkgs-fmt] | -| package.json | [sort-package-json] | -| Perl | [perlcritic], [perltidy] | -| PHP | [php-cs-fixer], [phpstan] | -| PNG | [oxipng] | -| PowerShell | [psscriptanalyzer] | -| Prisma | [prisma] | -| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | -| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [pylint], [pyright], [semgrep], [yapf], [ruff], [sourcery] | -| Rego | [regal], [opa] | -| Renovate | [renovate] | -| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | -| Rust | [clippy], [rustfmt] | -| Scala | [scalafmt] | -| Security | [checkov], [dustilock], [nancy], [osv-scanner], [snyk], [tfsec], [trivy], [trufflehog], [terrascan] | -| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | -| SVG | [svgo] | -| Swift | [stringslint], [swiftlint], [swiftformat] | -| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | -| Terragrunt | [terragrunt] | -| Textproto | [txtpbfmt] | -| TOML | [taplo] | -| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | -| YAML | [prettier], [semgrep], [yamllint] | +| Technology | Linters | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| All | [codespell], [cspell], [gitleaks], [git-diff-check], [pre-commit-hooks], [trunk-toolbox], [vale] | +| Ansible | [ansible-lint] | +| Apex | [pmd] | +| Bash | [shellcheck], [shfmt] | +| Bazel, Starlark | [buildifier] | +| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | +| C# | [dotnet-format] | +| CircleCI Config | [circleci] | +| Cloudformation | [cfnlint], [checkov] | +| CMake | [cmake-format] | +| CSS, SCSS | [stylelint], [prettier] | +| Cue | [cue-fmt] | +| Dart | [dart] | +| Docker | [hadolint], [checkov] | +| Dotenv | [dotenv-linter] | +| GitHub | [actionlint] | +| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | +| GraphQL | [graphql-schema-linter], [prettier] | +| HAML | [haml-lint] | +| HTML Templates | [djlint] | +| Java | [google-java-format], [pmd], [semgrep] | +| Javascript | [biome], [deno], [eslint], [prettier], [rome], [semgrep] | +| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | +| Kotlin | [detekt], [ktlint] | +| Kubernetes | [kube-linter] | +| Lua | [stylua] | +| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint] | +| Nix | [nixpkgs-fmt] | +| package.json | [sort-package-json] | +| Perl | [perlcritic], [perltidy] | +| PHP | [php-cs-fixer], [phpstan] | +| PNG | [oxipng] | +| PowerShell | [psscriptanalyzer] | +| Prisma | [prisma] | +| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | +| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [pylint], [basedpyright], [pyright], [semgrep], [yapf], [ruff], [sourcery] | +| Rego | [regal], [opa] | +| Renovate | [renovate] | +| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | +| Rust | [clippy], [rustfmt] | +| Scala | [scalafmt] | +| Security | [checkov], [dustilock], [nancy], [osv-scanner], [snyk], [tfsec], [trivy], [trufflehog], [terrascan] | +| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | +| SVG | [svgo] | +| Swift | [stringslint], [swiftlint], [swiftformat] | +| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | +| Terragrunt | [terragrunt] | +| Textproto | [txtpbfmt] | +| TOML | [taplo] | +| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | +| YAML | [prettier], [semgrep], [yamllint] | [actionlint]: https://trunk.io/linters/infra/actionlint [ansible-lint]: https://github.com/ansible/ansible-lint#readme @@ -157,6 +157,7 @@ trunk check enable {linter} [prisma]: https://github.com/prisma/prisma#readme [psscriptanalyzer]: https://github.com/PowerShell/PSScriptAnalyzer [pylint]: https://github.com/PyCQA/pylint#readme +[basedpyright]: https://github.com/DetachHead/basedpyright [pyright]: https://github.com/microsoft/pyright [regal]: https://github.com/StyraInc/regal#readme [remark-lint]: https://github.com/remarkjs/remark-lint#readme diff --git a/linters/basedpyright/plugin.yaml b/linters/basedpyright/plugin.yaml index aca5eab77..4c8923054 100644 --- a/linters/basedpyright/plugin.yaml +++ b/linters/basedpyright/plugin.yaml @@ -11,7 +11,9 @@ lint: - name: basedpyright files: [python] suggest_if: config_present - description: Basedpyright is a fork of pyright with various type checking improvements, pylance features and more + description: + Basedpyright is a fork of pyright with various type checking improvements, pylance features + and more commands: - name: lint output: sarif From 6728d358355196a67413450ee9eba76a2d2ba89f Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 5 Mar 2025 16:36:33 +0200 Subject: [PATCH 4/5] chore: Update test with circular deps --- linters/basedpyright/basedpyright_to_sarif.py | 22 +++++++++++++------ linters/basedpyright/test_data/basic.in.py | 7 +++++- .../test_data/circular_dependency.py | 8 +++++++ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 linters/basedpyright/test_data/circular_dependency.py diff --git a/linters/basedpyright/basedpyright_to_sarif.py b/linters/basedpyright/basedpyright_to_sarif.py index 5efa2bfaa..0ad045640 100755 --- a/linters/basedpyright/basedpyright_to_sarif.py +++ b/linters/basedpyright/basedpyright_to_sarif.py @@ -14,13 +14,21 @@ "artifactLocation": { "uri": result["file"], }, - "region": { - "startLine": result["range"]["start"]["line"] - + 1, # basedpyright is 0-indexed, SARIF is 1-indexed - "startColumn": result["range"]["start"]["character"] + 1, - "endLine": result["range"]["end"]["line"] + 1, - "endColumn": result["range"]["end"]["character"] + 1, - }, + # Add region only if range information is available + **( + { + "region": { + "startLine": result["range"]["start"]["line"] + + 1, # basedpyright is 0-indexed, SARIF is 1-indexed + "startColumn": result["range"]["start"]["character"] + + 1, + "endLine": result["range"]["end"]["line"] + 1, + "endColumn": result["range"]["end"]["character"] + 1, + } + } + if "range" in result + else {} + ), } } ], diff --git a/linters/basedpyright/test_data/basic.in.py b/linters/basedpyright/test_data/basic.in.py index 291049af6..19783199f 100644 --- a/linters/basedpyright/test_data/basic.in.py +++ b/linters/basedpyright/test_data/basic.in.py @@ -1,9 +1,14 @@ from typing import Callable, Iterator, Union, Optional, Enum - +# Create import cycle by importing from a module that will import this module +from circular_dependency import some_function def wrong_type(x: int) -> str: return x # error: Incompatible return value type (got "int", expected "str") +# Export something for the circular module to import +def function_for_circular_import(): + return "This function will be imported in circular_dependency.py" + class A: def method1(self) -> None: self.x = 1 diff --git a/linters/basedpyright/test_data/circular_dependency.py b/linters/basedpyright/test_data/circular_dependency.py new file mode 100644 index 000000000..dff6e59c6 --- /dev/null +++ b/linters/basedpyright/test_data/circular_dependency.py @@ -0,0 +1,8 @@ +# Import from the module that imports this module +from basic.in import function_for_circular_import + +def some_function(): + return "This creates a circular import with basic.in.py" + +# Use the imported function to complete the cycle +result = function_for_circular_import() From 38234efbcb43bd30fa4d48b206f8fb6686925595 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Thu, 6 Mar 2025 12:16:25 +0200 Subject: [PATCH 5/5] chore: Update test --- linters/basedpyright/basedpyright_to_sarif.py | 1 + ... => basedpyright_v1.28.1_basic.check.shot} | 59 +++++++++---------- linters/basedpyright/test_data/basic.in.py | 13 ++-- .../test_data/circular_dependency.py | 8 --- 4 files changed, 34 insertions(+), 47 deletions(-) rename linters/basedpyright/test_data/{pyright_v1.28.1_basic.check.shot => basedpyright_v1.28.1_basic.check.shot} (92%) delete mode 100644 linters/basedpyright/test_data/circular_dependency.py diff --git a/linters/basedpyright/basedpyright_to_sarif.py b/linters/basedpyright/basedpyright_to_sarif.py index 0ad045640..b7d9aafa0 100755 --- a/linters/basedpyright/basedpyright_to_sarif.py +++ b/linters/basedpyright/basedpyright_to_sarif.py @@ -15,6 +15,7 @@ "uri": result["file"], }, # Add region only if range information is available + # e.g. reportImportCycles does not have "range" information **( { "region": { diff --git a/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot b/linters/basedpyright/test_data/basedpyright_v1.28.1_basic.check.shot similarity index 92% rename from linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot rename to linters/basedpyright/test_data/basedpyright_v1.28.1_basic.check.shot index b07b6edf7..5277e0904 100644 --- a/linters/basedpyright/test_data/pyright_v1.28.1_basic.check.shot +++ b/linters/basedpyright/test_data/basedpyright_v1.28.1_basic.check.shot @@ -1,5 +1,4 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -// trunk-upgrade-validation:RELEASE exports[`Testing linter basedpyright test basic 1`] = ` { @@ -203,15 +202,15 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "18", "linter": "basedpyright", "message": "Cannot assign to attribute "x" for class "A" - Expression of type "float" cannot be assigned to attribute "x" of class "A" - Type "float" is not assignable to type "int | str" - "float" is not assignable to "int" - "float" is not assignable to "str"", +  Expression of type "float" cannot be assigned to attribute "x" of class "A" +    Type "float" is not assignable to type "int | str" +      "float" is not assignable to "int" +      "float" is not assignable to "str"", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "467", + "offset": "462", }, ], "targetType": "python", @@ -230,7 +229,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "609", + "offset": "599", }, ], "targetType": "python", @@ -249,7 +248,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "8", - "offset": "612", + "offset": "602", }, ], "targetType": "python", @@ -263,12 +262,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "level": "LEVEL_MEDIUM", "line": "27", "linter": "basedpyright", - "message": "Type annotation for attribute `z` is required because this class is not decorated with `@final`", + "message": "Type annotation for attribute \`z\` is required because this class is not decorated with \`@final\`", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "690", + "offset": "680", }, ], "targetType": "python", @@ -283,12 +282,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "30", "linter": "basedpyright", "message": "Argument type is unknown - Argument corresponds to parameter "values" in function "print"", +  Argument corresponds to parameter "values" in function "print"", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "739", + "offset": "729", }, ], "targetType": "python", @@ -307,7 +306,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "739", + "offset": "729", }, ], "targetType": "python", @@ -322,12 +321,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "31", "linter": "basedpyright", "message": "Argument type is unknown - Argument corresponds to parameter "values" in function "print"", +  Argument corresponds to parameter "values" in function "print"", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "750", + "offset": "740", }, ], "targetType": "python", @@ -346,7 +345,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "750", + "offset": "740", }, ], "targetType": "python", @@ -361,12 +360,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "31", "linter": "basedpyright", "message": "Cannot access attribute "z" for class "type[A]" - Attribute "z" is unknown", +  Attribute "z" is unknown", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "1", - "offset": "752", + "offset": "742", }, ], "targetType": "python", @@ -385,7 +384,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "4", - "offset": "818", + "offset": "803", }, ], "targetType": "python", @@ -399,12 +398,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "level": "LEVEL_MEDIUM", "line": "36", "linter": "basedpyright", - "message": "Type annotation for attribute `RED` is required because this class is not decorated with `@final`", + "message": "Type annotation for attribute \`RED\` is required because this class is not decorated with \`@final\`", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "829", + "offset": "814", }, ], "targetType": "python", @@ -418,12 +417,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "level": "LEVEL_MEDIUM", "line": "37", "linter": "basedpyright", - "message": "Type annotation for attribute `BLUE` is required because this class is not decorated with `@final`", + "message": "Type annotation for attribute \`BLUE\` is required because this class is not decorated with \`@final\`", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "4", - "offset": "841", + "offset": "826", }, ], "targetType": "python", @@ -438,12 +437,12 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "39", "linter": "basedpyright", "message": "Function with declared return type "bool" must return value on all code paths - "None" is not assignable to "bool"", +  "None" is not assignable to "bool"", "ranges": [ { "filePath": "test_data/basic.in.py", "length": "4", - "offset": "879", + "offset": "864", }, ], "targetType": "python", @@ -458,7 +457,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` "line": "5", "linter": "basedpyright", "message": "Type "int" is not assignable to return type "str" - "int" is not assignable to "str"", +  "int" is not assignable to "str"", "ranges": [ { "filePath": "test_data/basic.in.py", @@ -481,7 +480,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "1143", + "offset": "1128", }, ], "targetType": "python", @@ -499,7 +498,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "3", - "offset": "1259", + "offset": "1244", }, ], "targetType": "python", @@ -518,7 +517,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` { "filePath": "test_data/basic.in.py", "length": "9", - "offset": "1295", + "offset": "1280", }, ], "targetType": "python", @@ -551,7 +550,7 @@ exports[`Testing linter basedpyright test basic 1`] = ` "level": "LEVEL_MEDIUM", "line": "9", "linter": "basedpyright", - "message": "Type annotation for attribute `x` is required because this class is not decorated with `@final`", + "message": "Type annotation for attribute \`x\` is required because this class is not decorated with \`@final\`", "ranges": [ { "filePath": "test_data/basic.in.py", diff --git a/linters/basedpyright/test_data/basic.in.py b/linters/basedpyright/test_data/basic.in.py index 19783199f..69879b580 100644 --- a/linters/basedpyright/test_data/basic.in.py +++ b/linters/basedpyright/test_data/basic.in.py @@ -1,14 +1,9 @@ from typing import Callable, Iterator, Union, Optional, Enum -# Create import cycle by importing from a module that will import this module -from circular_dependency import some_function + def wrong_type(x: int) -> str: return x # error: Incompatible return value type (got "int", expected "str") -# Export something for the circular module to import -def function_for_circular_import(): - return "This function will be imported in circular_dependency.py" - class A: def method1(self) -> None: self.x = 1 @@ -19,8 +14,8 @@ def method2(self) -> None: a = A() reveal_type(a.x) -a.x = "" # Basedpyright allows this because the type of `x` is `int | str` -a.x = 3.0 # Basedpyright treats this as an error because the type of `x` is `int | str` +a.x = "" # Pyright allows this because the type of `x` is `int | str` +a.x = 3.0 # Pyright treats this as an error because the type of `x` is `int | str` @@ -33,7 +28,7 @@ def __init__(self): print(A.x) print(A.y) -print(A.z) # basedpyright shows error, mypy shows no error +print(A.z) # pyright shows error, mypy shows no error diff --git a/linters/basedpyright/test_data/circular_dependency.py b/linters/basedpyright/test_data/circular_dependency.py deleted file mode 100644 index dff6e59c6..000000000 --- a/linters/basedpyright/test_data/circular_dependency.py +++ /dev/null @@ -1,8 +0,0 @@ -# Import from the module that imports this module -from basic.in import function_for_circular_import - -def some_function(): - return "This creates a circular import with basic.in.py" - -# Use the imported function to complete the cycle -result = function_for_circular_import()