From ed150befe14139f67a112618f4241f80a305669f Mon Sep 17 00:00:00 2001 From: detachhead Date: Mon, 30 Sep 2024 19:33:50 +1000 Subject: [PATCH] fix some outdated info in the docs, improve some wording and add some more info about baseline --- docs/benefits-over-pyright/baseline.md | 9 ++++- .../new-diagnostic-rules.md | 38 ++++++++++++------ .../unreachable-hint.png | Bin 0 -> 2580 bytes docs/configuration/command-line.md | 24 ++++++++--- docs/configuration/comments.md | 16 +++++++- docs/configuration/config-files.md | 10 +++-- .../command-line-and-language-server.md | 2 +- docs/installation/ides.md | 10 ++--- docs/installation/pre-commit hook.md | 4 +- docs/usage/commands.md | 17 ++++++-- 10 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 docs/benefits-over-pyright/unreachable-hint.png diff --git a/docs/benefits-over-pyright/baseline.md b/docs/benefits-over-pyright/baseline.md index e6d89d632..9d10b52b1 100644 --- a/docs/benefits-over-pyright/baseline.md +++ b/docs/benefits-over-pyright/baseline.md @@ -4,7 +4,14 @@ have you ever wanted to adopt a new tool or enable new checks in an existing pro to enable baseline, run `basedpyright --writebaseline` in your terminal or run the _"basedpyright: Write new errors to baseline"_ task in vscode. this will generate a `./basedpyright/baseline.json` for your project. you should commit this file so others working on your project can benefit from it too. -this file gets automatically updated as errors are removed over time in both the CLI and the language server. if you ever need to baseline new errors or an error that resurfaced because you've modified the same line of code it was on, just run that command again. +## how often do i need to update the baseline file? + +this file gets automatically updated as errors are removed over time in both the CLI and the language server. you should only manually run the write baseline command in the following scenarios: + +- a baselined error incorrectly resurfaces when updating unrelated code +- you're enabling a new diagnostic rule and want to baseline all the new errors it reported + +if you need to suppress a diagnostic for another reason, consider using [a `# pyright: ignore` comment](../configuration/comments.md#prefer-pyrightignore-comments) instead. ## how does it work? diff --git a/docs/benefits-over-pyright/new-diagnostic-rules.md b/docs/benefits-over-pyright/new-diagnostic-rules.md index 92e58f406..5130fe22d 100644 --- a/docs/benefits-over-pyright/new-diagnostic-rules.md +++ b/docs/benefits-over-pyright/new-diagnostic-rules.md @@ -1,19 +1,29 @@ # new diagnostic rules +this section lists all of the new diagnostic rules that are exclusive to basedpyright and the motivationbehind them. for a complete list of all diagnostic rules, [see here](../configuration/config-files.md#type-check-rule-overrides). + ## `reportUnreachable` -pyright often incorrectly marks code as unreachable. in most cases, unreachable code is a mistake and therefore should be an error, but pyright does not have an option to report unreachable code. in fact, unreachable code is not even type-checked at all: +pyright often incorrectly marks code as unreachable. in most cases, unreachable code is a mistake and therefore should be an error, but pyright does not have an option to report unreachable code as an error, only as agreyed-out hint in your IDE: ```py if sys.platform == "win32": - 1 + "" # no error + do_thing() # no error ``` +![](unreachable-hint.png) + +this is very easy to miss, especially since it doesn't cause the CLI to fail so such a mistake could easily pass your CI. + by default, pyright will treat the body in the code above as unreachable if pyright itself was run on an operating system other than windows. this is bad of course, because chances are if you write such a check, you intend for your code to be executed on multiple platforms. -to make things worse, unreachable code is not even type-checked, so the obviously invalid `1 + ""` above will go completely unnoticed by the type checker. +to make things worse, unreachable code is not even type-checked at all! so if the code is reached, and the `do_thing` function isn't being called with the correct arguments, pyright will not complain! + +`reportUnreachable` solves this problem by reporting unreachable code as an error by default. -basedpyright solves this issue with a `reportUnreachable` option, which will report an error on such unchecked code. in this example, you can [update your pyright config to specify more platforms using the `pythonPlatform` option](https://github.com/detachhead/basedpyright/blob/main/docs/configuration.md#main-configuration-options) if you intend for the code to be reachable. +!!! note + + the above example with `sys.platform` won't happen by default in basedpyright anyway, because [we've changed the default `pythonPlatform` to `"All"`](./better-defaults.md#pythonplatform). but other cases such as python version checks will still benefit from this rule. ## `reportAny` @@ -37,7 +47,9 @@ it's good practice to specify an error code in your `pyright: ignore` comments: this way, if the error changes or a new error appears on the same line in the future, you'll get a new error because the comment doesn't account for the other error. -note that `type: ignore` comments (`enableTypeIgnoreComments`) are unsafe and are disabled by default (see [#330](https://github.com/DetachHead/basedpyright/issues/330) and [#55](https://github.com/DetachHead/basedpyright/issues/55)). we recommend using `pyright: ignore` comments instead. +!!! note + + `type: ignore` comments ([`enableTypeIgnoreComments`](../configuration/config-files.md#enableTypeIgnoreComments)) are unsafe and are disabled by default (see [#330](https://github.com/DetachHead/basedpyright/issues/330) and [#55](https://github.com/DetachHead/basedpyright/issues/55)). we recommend using `pyright: ignore` comments instead. ## `reportPrivateLocalImportUsage` @@ -106,18 +118,18 @@ cast(str, foo) in this example, it's impossible to be `foo` to be a `str` if it's also an `int`, because the `int` and `str` types do not overlap. the `reportInvalidCast` rule will report invalid casts like these. -### note about casting with `TypedDict`s +!!! note "note about casting with `TypedDict`s" -a common use case of `cast` is to convert a regular `dict` into a `TypedDict`: + a common use case of `cast` is to convert a regular `dict` into a `TypedDict`: -```py -foo: dict[str, int | str] -bar = cast(dict[{"foo": int, "bar": str}], foo) -``` + ```py + foo: dict[str, int | str] + bar = cast(dict[{"foo": int, "bar": str}], foo) + ``` -unfortunately, this will cause a `reportInvalidCast` error when this rule is enabled, because although at runtime `TypedDict` is a `dict`, type checkers treat it as an unrelated subtype of `Mapping` that doesn't have a `clear` method, which would break its type-safety if it were to be called on a `TypedDict`. + unfortunately, this will cause a `reportInvalidCast` error when this rule is enabled, because although at runtime `TypedDict` is a `dict`, type checkers treat it as an unrelated subtype of `Mapping` that doesn't have a `clear` method, which would break its type-safety if it were to be called on a `TypedDict`. -this means that although casting between them is a common use case, `TypedDict`s and `dict`s technically do not overlap. + this means that although casting between them is a common use case, `TypedDict`s and `dict`s technically do not overlap. ## `reportUnsafeMultipleInheritance` diff --git a/docs/benefits-over-pyright/unreachable-hint.png b/docs/benefits-over-pyright/unreachable-hint.png new file mode 100644 index 0000000000000000000000000000000000000000..f6096f240d4033848498f40588125b379d9b000e GIT binary patch literal 2580 zcmV+v3hVWWP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D38_g$K~#8N?VL?) z8^;yL|D+GT7?x>4_CZKd%VaATNx`5>1Ih&oRDe}VZt4qtDAb-B(kKu>wj}t{oE#t) z+?oOm)S@m0Dz%5`VyhM@$r0SNu-r%rY_v%un;%LX^w1g-?Nf7zIDNC6{UVnXsqc;6 z4|w3t%+BoF;l6$E&2s4xq9DL9%$~=qJ{gADy}*fsK`6Tml;_ z!?*-CR)%p2TW72(4?G@IVkuScb}~aa?e)?*dC@+UQI*?3>VkF*UA{K+w;sz0OdLCo zvHtgg*#V3lKaPpSvTEERbRBd(N`86pS-)zN(v?77)oaMUr1Mz+Y*ByOXS?*T*;q3} z9=cdn!GWQ7fTR!*N)ln!;CB4IxL+thBx9(^8HqHo*E9I;fB%CXlJ39|CPs3qu{iEO0)N-qH0jG= zQW~a?roRV=1Dn&o7BpkMckdonR#vo%O89#P=6Y4ZfhCeaag(W=G(JV^-kZM?Z*P_M zc)EH!MIrV4G|s%h+t5JQeZBZ%lXxSx0VC*QIb$Mt$WNX(J3>S1u5PAC<#e9`2E zVsxO4Hd*9xP9HG7e642aba6kqk5(hEnFH{a_E&Ayko`QK(-=w((K)LAvRqHJOJTCv zw|Eg77pZFN8W};Cbsx)xoEiE7&0jZ09$cdNQ~Q*}z;b?!^J|aW&P|^WIi@i;bPn-! z5-~5GpPUb^j=Z~JTBQ+4;#ilD@#0C(ikW-j2N0tyBFlQab7%8UHp882w+?`ukOLEku*U=6JM~NCLNNUf_9* zD}my%rF13eJK4m|(@qMvFlqNv;hRXGU&5Ud@Bd2t351d8h7r~`qrV1q*9e_ITi3ko zWEkws2^^s~;stGKi#*!m&N4oq0FLN!Yc2fz5`rhx3{qZ+w3(CY$Z*#wXEo3~_;oaV zXok$S6UK01jUtX=im+;nH=OY9s-bH5(K}}eq0+6mLSby$@=b>aB6#mw(RxzXmT*qL z`ZTEj{WXy1vGuP#k`3Y1hLgn%ve9zq$0l!L$AokBtKqb%`ZK4W1{AbJnOr zBZE7iw&HAEF4DdD&d`a@%#e3&(YBwy{xiIgi#c0ltI}gzbKQL6EqpA@oK(w^f9prL zu?V${NBt#_Z`Ngta#p$vI>yJkPCPL3yYR@#>5rt2)nF>>KOD>6@{oHJJ} zFZao9J@2EOHcWY@%r$MI@=7gVRdq5Km1TXOzPoA+Ii{+U68@c7HFDMp3}%@94jU`OxCAy1kf+>gT!EroNrC=nA z#&i}ZJKKzlHa9(paeas84n%v*wyNY8F*Y)bf2*QSb4S!PJPL)Um9EsP0+ksebAUn8(m=itHi3jK@vn+~)E zoz-&Wqvav6m1nkvCx)@ZIqOzK#@wtn%UG?Rmo{+-%v51}jn#J&jZ5>kmD>E`oRPmu zPZYo$?2E8@WLFw-vYHDj;~7?sF=URsQ;%!P_0P?h=g=Ar9<&~%v#a1e^E5`I{D)|U zslfIxFqJL>1v}93Y!v0oyT}(GgW)uYAs`R<5)$eU|;S1t6bg zamb2VM6!-6_y7KCNq?!NUH|5w41)vcaX5ke#|11jcyZ<>RiX1j;Ex{wU2jwmlbQVu zzt6hWNCTfg>S(N$jIyE;GmHh!S+|&cc8TKI3jUEo;gC-tSMm#{g`5Ykv7s{Sz@Bx} zSf8^J4$oH^W-Hjk##)}smcfR>>?7E-GK@>$oRwi*0vjvCxCAyz0R0Qf(QSK5WC`Md)F0000basedpyright +updated ./.basedpyright/baseline.json with 200 errors (went down by 5) +0 errors, 0 warnings, 0 notes +``` + +the `--writebaseline` argument is only required if you are intentionally writing new errors to the baseline file. for more information about when to use this argument, [see here](../benefits-over-pyright/baseline.md#how-often-do-i-need-to-update-the-baseline-file). \ No newline at end of file diff --git a/docs/configuration/comments.md b/docs/configuration/comments.md index a91780aa1..c8c4a240c 100644 --- a/docs/configuration/comments.md +++ b/docs/configuration/comments.md @@ -30,10 +30,24 @@ Diagnostic levels are also supported. ## Line-level Diagnostic Suppression -PEP 484 defines a special comment `# type: ignore` that can be used at the end of a line to suppress all diagnostics emitted by a type checker on that line. Pyright supports this mechanism. +PEP 484 defines a special comment `# type: ignore` that can be used at the end of a line to suppress all diagnostics emitted by a type checker on that line. Pyright supports this mechanism. this is disabled by default in basedpyright. [see below](#prefer-pyrightignore-comments) for more information. Pyright also supports a `# pyright: ignore` comment at the end of a line to suppress all Pyright diagnostics on that line. This can be useful if you use multiple type checkers on your source base and want to limit suppression of diagnostics to Pyright only. The `# pyright: ignore` comment accepts an optional list of comma-delimited diagnostic rule names surrounded by square brackets. If such a list is present, only diagnostics within those diagnostic rule categories are suppressed on that line. For example, `# pyright: ignore [reportPrivateUsage, reportGeneralTypeIssues]` would suppress diagnostics related to those two categories but no others. If the `reportUnnecessaryTypeIgnoreComment` configuration option is enabled, any unnecessary `# type: ignore` and `# pyright: ignore` comments will be reported so they can be removed. + +### prefer `# pyright:ignore` comments + +`# pyright:ignore` comments are preferred over `# type:ignore` comments because they are more strict than `#type:ignore` comments: + +- `# type:ignore` comments will always suppress all errors on the line, regardless of what diagnostic rules are specified in brackets +- `# type:ignore` comments are not checked to ensure that the specified rule is valud: + ```py + # no error here, even though you are suppressing an invalid diagnostic code. + 1 + "" # type:ignore[asdf] + ``` + this decision was probably made to support other type checkers like mypy which use different codes to pyright, but in that case you should just disable `enableTypeIgnoreComments` to prevent pyright from looking at them. + +in basedpyright, `enableTypeIgnoreComments` is disabled by default to avoid these issues. \ No newline at end of file diff --git a/docs/configuration/config-files.md b/docs/configuration/config-files.md index 27fb21858..4a100eece 100644 --- a/docs/configuration/config-files.md +++ b/docs/configuration/config-files.md @@ -1,14 +1,18 @@ ## Pyright Configuration -Pyright offers flexible configuration options specified in a JSON-formatted text configuration. By default, the file is called “pyrightconfig.json” and is located within the root directory of your project. Multi-root workspaces (“Add Folder to Workspace…”) are supported, and each workspace root can have its own “pyrightconfig.json” file. For a sample pyrightconfig.json file, see [below](../configuration/config-files.md#sample-config-file). +basedpyright offers flexible configuration options specified in a JSON-formatted text configuration. By default, the file is called “pyrightconfig.json” and is located within the root directory of your project. Multi-root workspaces (“Add Folder to Workspace…”) are supported, and each workspace root can have its own “pyrightconfig.json” file. For a sample pyrightconfig.json file, see [below](../configuration/config-files.md#sample-config-file). -Pyright settings can also be specified in a `[tool.basedpyright]` section of a “pyproject.toml” file. A “pyrightconfig.json” file always takes precedent over “pyproject.toml” if both are present. For a sample pyproject.toml file, see [below](../configuration/config-files.md#sample-pyprojecttoml-file). +basedpyright settings can also be specified in a `[tool.basedpyright]` section of a “pyproject.toml” file. A “pyrightconfig.json” file always takes precedent over “pyproject.toml” if both are present. For a sample pyproject.toml file, see [below](../configuration/config-files.md#sample-pyprojecttoml-file). + +!!! info + + the `[tool.pyright]` section in `pyproject.toml` is also supported for backwards compatibility with existing pyright configs. Relative paths specified within the config file are relative to the config file’s location. Paths with shell variables (including `~`) are not supported. Paths within a config file should generally be relative paths so the config file can be shared by other developers who contribute to the project. ## Environment Options -The following settings control the *environment* in which Pyright will check for diagnostics. These settings determine how Pyright finds source files, imports, and what Python version specific rules are applied. +The following settings control the *environment* in which basedpyright will check for diagnostics. These settings determine how Pyright finds source files, imports, and what Python version specific rules are applied. - **include** [array of paths, optional]: Paths of directories or files that should be considered part of the project. If no paths are specified, pyright defaults to the directory that contains the config file. Paths may contain wildcard characters ** (a directory or multiple levels of directories), * (a sequence of zero or more characters), or ? (a single character). If no include paths are specified, the root path for the workspace is assumed. diff --git a/docs/installation/command-line-and-language-server.md b/docs/installation/command-line-and-language-server.md index 162a1932d..7d9f07629 100644 --- a/docs/installation/command-line-and-language-server.md +++ b/docs/installation/command-line-and-language-server.md @@ -54,4 +54,4 @@ once installed, the `basedpyright` and `basedpyright-langserver` scripts will be basedpyright --help ``` -for instructions on how to use `basedpyright-langserver`, see the [IDE-specific instructions below](./ides.md). +for instructions on how to use `basedpyright-langserver`, see the [IDE-specific instructions](./ides.md). diff --git a/docs/installation/ides.md b/docs/installation/ides.md index 3daca09d2..8024c3fca 100644 --- a/docs/installation/ides.md +++ b/docs/installation/ides.md @@ -22,10 +22,12 @@ install the extension from [the vscode extension marketplace](https://marketplac clicking "Fix settings & keep both extensions" will set the following settings for you automatically: - ```jsonc - // .vscode/settings.json + ```json title=".vscode/settings.json" { + // disable pylance's type checking and only use its language server "python.analysis.typeCheckingMode": "off", + + // disable basedpyright's language server and only use its type checking "basedpyright.disableLanguageServices": true } ``` @@ -40,9 +42,7 @@ the basedpyright extension will automatically look for the pypi package in your if you're adding basedpyright as a development dependency in your project, we recommend adding it to the recommended extensions list in your workspace to prompt others working on your repo to install it: -```jsonc -// .vscode/extensions.json - +```json title=".vscode/extensions.json" { "recommendations": ["detachhead.basedpyright"] } diff --git a/docs/installation/pre-commit hook.md b/docs/installation/pre-commit hook.md index 8744649e8..7850531e8 100644 --- a/docs/installation/pre-commit hook.md +++ b/docs/installation/pre-commit hook.md @@ -1,8 +1,6 @@ # pre-commit hook -```yaml -# .pre-commit-config.yaml - +```yaml title=".pre-commit-config.yaml" repos: - repo: https://github.com/DetachHead/basedpyright-pre-commit-mirror rev: v1.13.0 # or whatever the latest version is at the time diff --git a/docs/usage/commands.md b/docs/usage/commands.md index 502887fb7..b8f0db122 100644 --- a/docs/usage/commands.md +++ b/docs/usage/commands.md @@ -1,11 +1,20 @@ -## VS Code Commands +# VS Code Commands -Pyright offers the following commands, which can be invoked from VS Code’s “Command Palette”, which can be accessed from the View menu or by pressing Cmd-Shift-P. +basedyright offers the following commands, which can be invoked from VS Code’s “Command Palette”, which can be accessed from the View menu or by pressing Cmd-Shift-P. -### Organize Imports +## Organize Imports This command reorders all imports found in the global (module-level) scope of the source file. As recommended in PEP8, imports are grouped into three groups, each separated by an empty line. The first group includes all built-in modules, the second group includes all third-party modules, and the third group includes all local modules. Within each group, imports are sorted alphabetically. And within each “from X import Y” statement, the imported symbols are sorted alphabetically. Pyright also rewraps any imports that don't fit within a single line, switching to multi-line formatting. -### Restart Server +!!! note + + we recommend using [ruff](https://docs.astral.sh/ruff/formatter/#sorting-imports) to organize your imports instead, because pyright does not provide a way to validate that imports are sorted via the CLI. + +## Restart Server This command forces the type checker to discard all of its cached type information and restart analysis. It is useful in cases where new type stubs or libraries have been installed. + + +## Write new errors to baseline + +writes any new errors to the [baseline](../benefits-over-pyright/baseline.md) file. the language server will automatically update it on-save if errors are removed from a file and no new errors were added. for more information about when to use this command, [see here](../benefits-over-pyright/baseline.md#how-often-do-i-need-to-update-the-baseline-file). \ No newline at end of file