Package: basedpyright
basedpyrightBasedpyright is a static type checker for Python that is built on top of the work done by thepyright project.why?the main motivation behind this fork was the fact that pyright has several serious issues that the maintainers didn't want to address, and many bugs that they consider to be intentional behavior. here is a list of some of its major problems that we've resolved in basedpyright:ability to pin the version used by vscodein pyright, if the vscode extension gets updated, you may see errors in your project that don't appear in the CI, or vice-versa. seethis issue.basedpyright fixes this problem by adding animportStrategyoption to the extension, which defaults to looking in your project for thebasedpyright pypi package.published as a pypi package - no nodejs requiredpyright is only published as an npm package, which requires you to install nodejs.the version on pypiis just an unofficial wrapper that installs node and the npm package the first time you invoke the cli,which is quite flaky.python developers should not be expected to have to install nodejs in order to typecheck their python code. it should just be a regular pypi package like mypy, ruff, and pretty much all other python tooling. this is why basedpyright isofficially published on pypi, which comes bundled with the npm package.reporting errors on unreachable codepyright 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:ifsys.platform=="win32":1+""# no errorby 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 invalid1 + ""above will go completely unnoticed by the type checker.basedpyright solves this issue with areportUnreachableoption, which will report an error on such unchecked code. in this example, you canupdate your pyright config to specify more platforms using thepythonPlatformoptionif you intend for the code to be reachable.errors on invalid configurationin 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.option to fully ban theAnytypepyright has a few options to ban "Unknown" types such asreportUnknownVariableType,reportUnknownParameterType, etc. but "Unknown" is not a real type, rather a distinction pyright uses used to representAnys that come from untyped code or unfollowed imports. if you want to ban all kinds ofAny, pyright has no way to do that:deffoo(bar,baz:Any)->Any:print(bar)# error: unknown typeprint(baz)# no errorbasedpyright introduces thereportAnyoption, which will report an error on usages of anything typed asAny.re-implementing pylance-exclusive featurespyright does not support code actions for import suggestions,because that feature is exclusive to the closed-source pylance extension. basedpyright re-implements this feature in its language server:for more information about the differences between pyright and pylance, seeherereporting errors on invalid "relative" importspyright allows invalid imports such as this:# ./module_name/foo.py:# ./module_name/bar.py:importfoo# wrong! should be `import module_name.foo` or `from module_name import foo`this may look correct at first glance, and will work when runningbar.pydirectly as a script, but when it's imported as a module, it will crash:# ./main.py:importmodule_name.bar# ModuleNotFoundError: No module named 'foo'basedpyright bans imports like this. if you want to do a relative import, the correct way to do it is by prefixing the module name with a.:# ./module_name/bar.py:import.foofixes for thereportRedeclarationandreportDuplicateImportrulespyright does not report redeclarations if the redeclaration has the same type:foo:int=1foo:int=2# no errornor does it care if you have a duplicated import in multiple differentimportstatements, or in aliases:fromfooimportbarfrombarimportbar# no errorfrombazimportfooasbaz,barasbaz# no errorpyright 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 defaultswe 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 basedpyrighttypeCheckingModeused to bebasic, but now defaults toall. in the future we intend to addbaselineto allow for easy adoption of more strict rules in existing codebases.pythonPlatformused 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,pythonPlatformdefaults toAll, which assumes your code can run on any operating system.basedmypy feature paritybasedmypyis 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 toport most of basedmypy's features to basedpyright, however as mentioned above our priority is to first fix the critical problems with pyright.pypi packagebasedpyright 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.>basedpyright--help
Usage:basedpyright[options]files...Options:--createstub<IMPORT>Createtypestubfile(s)forimport--dependenciesEmitimportdependencyinformation-h,--helpShowthishelpmessage--ignoreexternalIgnoreexternalimportsfor--verifytypes--level<LEVEL>Minimumdiagnosticlevel(errororwarning)--outputjsonOutputresultsinJSONformat-p,--project<FILEORDIRECTORY>Usetheconfigurationfileatthislocation--pythonplatform<PLATFORM>Analyzeforaspecificplatform(Darwin,Linux,Windows)--pythonpath<FILE>PathtothePythoninterpreter--pythonversion<VERSION>Analyzeforaspecificversion(3.3,3.4,etc.)--skipunannotatedSkipanalysisoffunctionswithnotypeannotations--statsPrintdetailedperformancestats-t,--typeshedpath<DIRECTORY>Usetypeshedtypestubsatthislocation-v,--venvpath<DIRECTORY>Directorythatcontainsvirtualenvironments--verboseEmitverbosediagnostics--verifytypes<PACKAGE>Verifytypecompletenessofapy.typedpackage--versionPrintPyrightversionandexit--warningsUseexitcodeof1ifwarningsarereported-w,--watchContinuetorunandwatchforchanges-Readfilesfromstdinvscode extensioninstallinstall the extension fromthe vscode extension marketplaceusagethe basedpyright vscode extension will automatically look for the pypi package in your python environment. see the recommended setup section below for more informationpylance vs basedpyrightpylance is microsoft's closed-source vscode extension built on top of the pyright language server with some additional exclusive functionality (see the pylance FAQ for more information). normally when the pylance extension is enabled, the pyright extension will disable itself to avoid conflicting with it. unfortunately since it's closed-source, there's no way for us to update it to use basedpyright instead. so we intend to re-implement its exclusive features in basedpyright.if you don't depend on any pylance-exclusive features, the recommended solution is 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 disable pylance's type checking and disable basedpyright's language server features. seethe recommended setup section belowfor details.recommended setupit'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.vscode/extensions.json{
  "recommendations": [
    "detachhead.basedpyright" // this will prompt developers working on your project to install the extension
  ],
  "unwantedRecommendations": [
    "ms-python.vscode-pylance" // if not using pylance (see below)
  ]
}.vscode/settings.jsonif not using pylanceremove any settings starting withpython.analysis, as they are not used by basedpyright. you should instead set these settings using thetool.basedpyright(ortool.pyright) section inpyroject.toml(see below)disable the built in language server support from the python extension, as it seems to conflict with basedpyright's language server:{"python.languageServer":"None"}if using pylancedisable 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}.github/workflows/check.yamljobs:check:steps:-run:...# checkout repo, install dependencies, etc-run:basedpyright# add this linepyproject.tomlwe recommend usingpdmorpoetryto manage your dependencies.[tool.pdm.dev-dependencies]# or the poetry equivalentdev=["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 disabletypeCheckingMode="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