|
before | after |
---|---|
basedpyright re-implements pylance's semantic highlighting along with some additional improvements:
- variables marked as
Final
have the correct "read-only" colour - supports the new
type
keyword in python 3.12 Final
variables are coloured as read-only
initial implementation of the semantic highlighting provider was adapted from the pyright-inlay-hints project.
inlay hints
basedpyright contains several improvements and bug fixes to the original implementation adapted from pyright-inlay-hints.
docstrings for compiled builtin modules
many of the builtin modules are written in c, meaning the pyright language server cannot statically inspect and display their docstrings to the user. unfortunately they are also not available in the .pyi
stubs for these modules, as the typeshed maintainers consider it to be too much of a maintanance nightmare.
pylance works around this problem by running a "docstring scraper" script on the user's machine, which imports compiled builtin modules, scrapes all the docstrings from them at runtime, then saves them so that the language server can read them. however this isn't ideal for a few reasons:
- only docstrings for modules and functions available on the user's current OS and python version will be generated. so if you're working on a cross-platform project, or code that's intended to be run on multiple versions of python, you won't be able to see docstrings for compiled builtin modules that are not available in your current python installation.
- the check to determine whether a builtin object is compiled is done at the module level, meaning modules like
re
andos
which have python source files but contain re-exports of compiled functions, are treated as if they are entirely written in python. this means many of their docstrings are still missing in pylance. - it's (probably) slower because these docstrings need to be scraped either when the user launches vscode, or when the user hovers over a builtin class/function (disclaimer: i don't actually know when it runs, because pylance is closed source)
basedpyright solves all of these problems by using docify to scrape the docstrings from all compiled builtin functions/classes for all currently supported python versions and all platforms (macos, windows and linux), and including them in the default typeshed stubs that come with the basedpyright package.
examples
here's a demo of basedpyright's builtin docstrings when running on windows, compared to pylance:
basedpyright
pylance
generating your own stubs with docstrings
basedpyright uses docify to add docstrings to its stubs. if you have third party compiled modules and you want basedpyright to see its docstrings, you can do the same:
python -m docify path/to/stubs/for/package --in-place
or if you're using a different version of typeshed, you can use the --if-needed
argument to replicate how basedpyright's version of typeshed is generated for your current platform and python version:
python -m docify path/to/typeshed/stdlib --if-needed --in-place
renaming packages and modules
when renaming a package or module, basedpyright will update all usages to the new name, just like pylance does:
errors on invalid configuration
in pyright, if you have any invalid config, it may or may not print a warning to the console, then it will continue type-checking and the exit code will be 0 as long as there were no type errors:
[tool.pyright]
mode = "strict" # wrong! the setting you're looking for is called `typeCheckingMode`
in this example, it's very easy for errors to go undetected because you thought you were on strict mode, but in reality pyright just ignored the setting and silently continued type-checking on "basic" mode.
to solve this problem, basedpyright will exit with code 3 on any invalid config.
fixes for the reportRedeclaration
and reportDuplicateImport
rules
pyright does not report redeclarations if the redeclaration has the same type:
foo: int = 1
foo: int = 2 # no error
nor does it care if you have a duplicated import in multiple different import
statements, or in aliases:
from foo import bar
from bar import bar # no error
from baz import foo as baz, bar as baz # no error
basedpyright solves both of these problems by always reporting an error on a redeclaration or an import with the same name as an existing import.
better defaults
we believe that type checkers and linters should be as strict as possible by default, making the user aware of all the available rules so they can more easily make informed decisions about which rules they don't want enabled in their project. that's why the following defaults have been changed in basedpyright
typeCheckingMode
used to be basic
, but now defaults to all
. in the future we intend to add baseline to allow for easy adoption of more strict rules in existing codebases.
pythonPlatform
used to assume that the operating system pyright is being run on is the only operating system your code will run on, which is rarely the case. in basedpyright, pythonPlatform
defaults to All
, which assumes your code can run on any operating system.
inline TypedDict
support
pyright used to support defining TypedDict
s inline, like so:
foo: dict[{"foo": int, "bar": str}] = {"foo": "a", "bar": 1}
this was an experimental feature and was removed because it never made it into a PEP. but this functionality is very convenient and we see no reason not to continue supporting it, so we added it back in basedpyright.
currently this can be disabled by setting enableExperimentalFeatures
to false
. in the future there will be a separate enableNonStandardFeatures
option once we add more "based" features.
improved integration with CI platforms
regular pyright has third party integrations for github actions and gitlab, but they are difficult to install/set up. these integrations are built into basedpyright, which makes them much easier to use.
github actions
basedpyright automatically detects when it's running in a github action, and modifies its output to use github workflow commands. this means errors will be displayed on the affected lines of code in your pull requests automatically:
this is an improvement to regular pyright, which requires you to use a third party action that requires boilerplate to get working. basedpyright just does it automatically without you having to do anything special:
# .github/workflows/your_workflow.yaml
jobs:
check:
steps:
- run: ... # checkout repo, install dependencies, etc
- run: basedpyright # no additional arguments required. it automatically detects if it's running in a github action
gitlab code quality reports
the --gitlabcodequality
argument will output a gitlab code quality report which shows up on merge requests:
to enable this in your gitlab CI, just specify a file path to output the report to, and in the artifacts.reports.codequality
section of your .gitlab-ci.yml
file:
basedpyright:
script: basedpyright --gitlabcodequality report.json
artifacts:
reports:
codequality: report.json
basedmypy feature parity
basedmypy is a fork of mypy with a similar goal in mind: to fix some of the serious problems in mypy that do not seem to be a priority for the maintainers. it also adds many new features which may not be standardized but greatly improve the developer experience when working with python's far-from-perfect type system.
we aim to port most of basedmypy's features to basedpyright, however as mentioned above our priority is to first fix the critical problems with pyright.
note that any non-standard features we add will be optional, as we intend to support library developers who can't control what type checker their library is used with.
pypi package
basedpyright differs from pyright by publishing the command line tool as a pypi package instead of an npm package. this makes it far more convenient for python developers to use, since there's no need to install any additional tools.
for more information, see the installation instructions.
vscode extension
install
install the extension from the vscode extension marketplace or the open VSX registry
usage
the basedpyright vscode extension will automatically look for the pypi package in your python environment.
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:
// .vscode/extensions.json
{
"recommendations": ["detachhead.basedpyright"]
}
in .vscode/settings.json
, remove any settings starting with python.analysis
, as they are not used by basedpyright. you should instead set these settings using the tool.basedpyright
(or tool.pyright
) section in pyroject.toml
(see below)
you should also disable the built in language server support from the python extension, as it conflicts with basedpyright's language server. the basedpyright extension will detect this problem and suggest fixing it automatically.
using basedpyright with pylance (not recommended)
unless you depend on any pylance-exclusive features that haven't yet been re-implemented in basedpyright, it's recommended to disable/uninstall the pylance extension.
if you do want to continue using pylance, all of the options and commands in basedpyright have been renamed to avoid any conflicts with the pylance extension, and the restriction that prevents both extensions from being enabled at the same time has been removed. for an optimal experience you should change the following settings in your .vscode/settings.json
file:
- disable pylance's type-checking by setting
"python.analysis.typeCheckingMode"
to"off"
. this will prevent pylance from displaying duplicated errors from its bundled pyright version alongside the errors already displayed by the basedpyright extension. - disable basedpyright's LSP features by setting
"basedpyright.disableLanguageServices"
totrue
. this will prevent duplicated hover text and other potential issues with pylance's LSP. keep in mind that this may result in some inconsistent behavior since pylance uses its own version of the pyright LSP.
{
"python.analysis.typeCheckingMode": "off",
"basedpyright.disableLanguageServices": true
}
(the basedpyright extension will detect this problem and suggest fixing it automatically)
playground
you can try basedpyright in your browser using the basedpyright playground
pre-commit hook
integration with pre-commit is also supported.
# .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
hooks:
- id: basedpyright
for more information, see the documentation here
recommended setup
it's recommended to use both the basedpyright cli and vscode extension in your project. the vscode extension is for local development and the cli is for your CI.
below are the changes i recommend making to your project when adopting basedpyright
pyproject.toml
we recommend using pdm with pyprojectx (click the "inside project" tab) to manage your dependencies.
[tool.pyprojectx]
main = ["pdm==2.12.4"] # installs pdm to your project instead of globally
[tool.pdm.dev-dependencies] # or the poetry equivalent
dev = [
"basedpyright", # you can pin the version here if you want, or just rely on the lockfile
]
[tool.basedpyright]
# many settings are not enabled even in strict mode, which is why basedpyright includes an "all" option
# you can then decide which rules you want to disable
typeCheckingMode = "all"
pinning your dependencies is important because it allows your CI builds to be reproducible (ie. two runs on the same commit will always produce the same result). basedpyright ensures that the version of pyright used by vscode always matches this pinned version.