"chore: migrate Pyright branding to Vipeye/vipeye across docs and tooling
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
Run mypy_primer on push / Run mypy_primer on push (push) Has been cancelled

- Rewrite root README and docs for Vipeye
- Rename pyright-test-policy to vipeye-test-policy
- Update CI/Azure pipelines, perfCompare.py and package metadata
- Keep upstream links, external tool params and # pyright: ignore compat"
This commit is contained in:
TermiNexus committed 2026-08-07 03:33:29 +08:00
1 parent be9ff90d11
commit 44d83f4235
76 files changed
+930 -1013

No files matched your search

+2 -2
View File
@@ -9,7 +9,7 @@ assignees: ''
Note: if you are reporting a wrong signature of a function or a class in the standard library, then the typeshed tracker is better suited for this report: https://github.com/python/typeshed/issues.
If you have a question about typing or a behavior that you’re seeing in Pyright (as opposed to a bug report or enhancement request), consider posting to the [Pyright discussion forum](https://github.com/microsoft/pyright/discussions).
If you have a question about typing or a behavior that you’re seeing in Vipeye (as opposed to a bug report or enhancement request), consider posting to the [Pyright discussion forum](https://github.com/microsoft/pyright/discussions).
**Describe the bug**
A clear and concise description of the behavior you are seeing and the expected behavior along with steps to reproduce it.
@@ -25,4 +25,4 @@ def foo(self) -> str:
If your code relies on symbols that are imported from a third-party library, include the associated import statements and specify which versions of those libraries you have installed.
**VS Code extension or command-line**
Are you running pyright as a VS Code extension, a language server in another editor, integrated into Pylance, or the command-line tool? Which version?
Are you running vipeye as a VS Code extension, a language server in another editor, integrated into Pylance, or the command-line tool? Which version?
+1 -1
View File
@@ -7,7 +7,7 @@ assignees: ''
---
If you have a question about a behavior that you’re seeing in pyright, consider posting to the [Pyright discussion forum](https://github.com/microsoft/pyright/discussions).
If you have a question about a behavior that you’re seeing in vipeye, consider posting to the [Pyright discussion forum](https://github.com/microsoft/pyright/discussions).
**Is your feature request related to a problem? Please describe.**
A clear and concise description of the problem.
+3 -3
View File
@@ -31,17 +31,17 @@ runs:
- uses: ./.github/actions/cfs-npm-authenticate
with:
working-directory: packages/pyright
working-directory: packages/vipeye
token: ${{ steps.npm-auth.outputs.token }}
- uses: ./.github/actions/cfs-npm-authenticate
with:
working-directory: packages/pyright-internal
working-directory: packages/vipeye-internal
token: ${{ steps.npm-auth.outputs.token }}
- uses: ./.github/actions/cfs-npm-authenticate
with:
working-directory: packages/vscode-pyright
working-directory: packages/vscode-vipeye
token: ${{ steps.npm-auth.outputs.token }}
- uses: ./.github/actions/cfs-npm-cache
+18 -18
View File
@@ -1,20 +1,20 @@
---
name: typeshed-update-agent
description: Updates Pyright bundled typeshed fallback and triages resulting test changes while preserving type precision.
description: Updates Vipeye bundled typeshed fallback and triages resulting test changes while preserving type precision.
---
# Typeshed Update Agent
This agent updates the typeshed version used by Pyright and ensures tests remain correct and precise.
This agent updates the typeshed version used by Vipeye and ensures tests remain correct and precise.
The agent must follow the **Pyright Test Policy**.
The agent must follow the **Vipeye Test Policy**.
---
# Phase 1 — Update Typeshed
1. Update the pinned typeshed commit or submodule.
2. Run the full Pyright test suite.
2. Run the full Vipeye test suite.
3. If all tests pass, create a PR titled:
Update typeshed to <commit>
@@ -25,7 +25,7 @@ Use the fork branch as the PR head if needed, and verify the reported PR URL is
## Running The Update Script
Use the repo script (from the Pyright repo root):
Use the repo script (from the Vipeye repo root):
```bash
python build/updateTypeshed.py
@@ -40,7 +40,7 @@ Notes:
- The script clones `https://github.com/python/typeshed.git` into a temporary directory.
- A local checkout of typeshed is not required to run the update.
- It updates `packages/pyright-internal/typeshed-fallback/` and writes the selected SHA to `packages/pyright-internal/typeshed-fallback/commit.txt`.
- It updates `packages/vipeye-internal/typeshed-fallback/` and writes the selected SHA to `packages/vipeye-internal/typeshed-fallback/commit.txt`.
- Do not spend token budget reviewing or summarizing the full generated `typeshed-fallback` diff; it is expected to be large and noisy. Use the pinned SHA, upstream compare links, and targeted file inspection only when tests fail or a specific behavior change needs triage.
## Upstream Investigation Guidance
@@ -51,7 +51,7 @@ When behavior changes are suspected, inspect upstream typeshed directly:
- compare SHAs: `https://github.com/python/typeshed/compare/<old_sha>...<new_sha>`
- specific PRs linked from changed files or commit history (for example dict constructor positional-only changes in `python/typeshed#15262`)
Always tie Pyright test changes to a concrete upstream typeshed commit or PR.
Always tie Vipeye test changes to a concrete upstream typeshed commit or PR.
---
@@ -62,7 +62,7 @@ If tests fail, the agent must classify each failure.
Possible categories:
A) Legitimate typeshed behavior change
B) Pyright bug revealed by new stubs
B) Vipeye bug revealed by new stubs
C) Test fragility (formatting / ordering)
D) Test harness or environment issue
@@ -107,11 +107,11 @@ Track changes including:
Run these focused tests before full-suite reruns when related files change.
- constructor callable and default constructor behavior:
- `cd packages/pyright-internal && npm run test:norebuild -- typeEvaluator6.test.ts -t "ConstructorCallable1|ConstructorCallable2|Constructor28" --runInBand`
- `cd packages/vipeye-internal && npm run test:norebuild -- typeEvaluator6.test.ts -t "ConstructorCallable1|ConstructorCallable2|Constructor28" --runInBand`
- contextmanager / generator behavior:
- `cd packages/pyright-internal && npm run test:norebuild -- typeEvaluator2.test.ts -t Solver7 --runInBand`
- `cd packages/vipeye-internal && npm run test:norebuild -- typeEvaluator2.test.ts -t Solver7 --runInBand`
- positional-only parameter behavior:
- `cd packages/pyright-internal && npm run test:norebuild -- typeEvaluator1.test.ts -t Call3 --runInBand`
- `cd packages/vipeye-internal && npm run test:norebuild -- typeEvaluator1.test.ts -t Call3 --runInBand`
---
@@ -119,7 +119,7 @@ Run these focused tests before full-suite reruns when related files change.
Preferred order:
1. Fix Pyright implementation
1. Fix Vipeye implementation
2. Patch incorrect typeshed stub
3. Update expected outputs (last resort)
@@ -132,7 +132,7 @@ Test updates must follow the **Precision Regression Rule**.
If type precision is reduced (e.g. `T → Unknown`):
1. Check whether a stub change caused the regression.
2. Attempt to restore precision via Pyright improvements.
2. Attempt to restore precision via Vipeye improvements.
3. If unavoidable, update tests **with justification**.
A regression report must be added to the PR.
@@ -140,7 +140,7 @@ A regression report must be added to the PR.
## Regression Guardrails
- Do not accept `T -> Unknown` precision drops without root-cause analysis.
- Do not update reveal expectations until checking whether a Pyright implementation fix can preserve precision.
- Do not update reveal expectations until checking whether a Vipeye implementation fix can preserve precision.
- If a reveal text changes due to upstream behavior, include the upstream commit/PR reference in the test update commit message or PR description.
---
@@ -150,7 +150,7 @@ A regression report must be added to the PR.
PR must include:
- typeshed commit bump
- Pyright fixes if needed
- Vipeye fixes if needed
- minimal test updates
- precision regression report (if applicable)
- explanation for each change
@@ -164,7 +164,7 @@ Include the following sections in the PR description:
- compare URL
2. Failure classification summary
- categories A/B/C/D with counts
3. Pyright fixes
3. Vipeye fixes
- files changed
- behavior restored
4. Test updates
@@ -182,7 +182,7 @@ Include the following sections in the PR description:
Preferred commits:
1. typeshed update
2. pyright fixes
2. vipeye fixes
3. justified test updates
Keeping these separate simplifies review.
@@ -203,4 +203,4 @@ Escalate early when any of these occur:
- constructor synthesis behavior changes in multiple unrelated samples
- new failures in both evaluator and language service suites from one stub change
- uncertainty about whether a fix belongs in Pyright versus upstream typeshed
- uncertainty about whether a fix belongs in Vipeye versus upstream typeshed
@@ -1,11 +1,11 @@
---
name: pyright-test-policy
description: Enforces Pyright test policy, preserving type precision and requiring justification for test changes.
name: vipeye-test-policy
description: Enforces Vipeye test policy, preserving type precision and requiring justification for test changes.
---
# Pyright Test Policy
# Vipeye Test Policy
Tests are the specification for Pyright behavior.
Tests are the specification for Vipeye behavior.
Agents must **not modify tests simply to make CI pass**.
@@ -18,7 +18,7 @@ The goal is to **preserve or improve type precision** unless a justified upstrea
Agents may modify tests only when one of the following is true:
1. A **typeshed stub change** legitimately alters the expected type.
2. A **Pyright diagnostic message format** changed but the semantic meaning is the same.
2. A **Vipeye diagnostic message format** changed but the semantic meaning is the same.
3. A test relied on unstable formatting or ordering.
---
@@ -49,11 +49,11 @@ These regressions are **allowed only with justification**.
- or an upstream typing change
2. **Reasoning**
- why Pyright cannot infer the previous precision
- why Vipeye cannot infer the previous precision
3. **Classification**
- A) typeshed became less precise
- B) Pyright limitation
- B) Vipeye limitation
- C) test fragility
- D) harness issue
@@ -81,7 +81,7 @@ without the justification process above.
Agents must attempt fixes in this order:
1. **Fix Pyright behavior**
1. **Fix Vipeye behavior**
2. **Fix incorrect typeshed stub**
3. **Adjust tests (last resort)**
+13 -13
View File
@@ -1,6 +1,6 @@
# Copilot Instructions for Pyright
# Copilot Instructions for Vipeye
Pyright is a static type checker for Viper, written in TypeScript. It ships as an npm CLI (`pyright`), an LSP language server (`pyright-langserver`), and a VS Code extension (`vscode-pyright`).
Vipeye is a static type checker for Viper, written in TypeScript. It ships as an npm CLI (`vipeye`), an LSP language server (`vipeye-langserver`), and a VS Code extension (`vscode-vipeye`).
## Build and Test
@@ -9,19 +9,19 @@ Pyright is a static type checker for Viper, written in TypeScript. It ships as a
npm install
# Build the core library
cd packages/pyright-internal && npm run build
cd packages/vipeye-internal && npm run build
# Run all tests (builds test server first)
cd packages/pyright-internal && npm test
cd packages/vipeye-internal && npm test
# Run all tests without rebuilding the test server (faster iteration)
cd packages/pyright-internal && npm run test:norebuild
cd packages/vipeye-internal && npm run test:norebuild
# Run a single test file
cd packages/pyright-internal && npx jest typeEvaluator1.test --forceExit
cd packages/vipeye-internal && npx jest typeEvaluator1.test --forceExit
# Run a single test by name
cd packages/pyright-internal && npx jest -t "Generic1" --forceExit
cd packages/vipeye-internal && npx jest -t "Generic1" --forceExit
# Build the CLI (webpack bundle)
npm run build:cli:dev
@@ -49,9 +49,9 @@ npm run fix:prettier
### Package Structure
- **`packages/pyright-internal`** — Core library: parser, binder, type evaluator, checker, language service. All logic lives here. This is the only package with tests.
- **`packages/pyright`** — CLI wrapper. Webpack-bundles `pyright-internal` into a distributable npm package with `pyright` and `pyright-langserver` entry points.
- **`packages/vscode-pyright`** — VS Code extension client that communicates with the language server.
- **`packages/vipeye-internal`** — Core library: parser, binder, type evaluator, checker, language service. All logic lives here. This is the only package with tests.
- **`packages/vipeye`** — CLI wrapper. Webpack-bundles `vipeye-internal` into a distributable npm package with `vipeye` and `vipeye-langserver` entry points.
- **`packages/vscode-vipeye`** — VS Code extension client that communicates with the language server.
### Analysis Pipeline
@@ -69,7 +69,7 @@ Source files are processed through these phases in order:
**Service → Program → SourceFile**: A `Service` manages a `Program`, which tracks `SourceFile` instances. The `Program` coordinates analysis ordering, prioritizing open editor files and their dependencies.
**Typeshed fallback**: `packages/pyright-internal/typeshed-fallback/` contains a bundled copy of typeshed stubs. This provides the Viper stdlib type stubs when no external typeshed is available.
**Typeshed fallback**: `packages/vipeye-internal/typeshed-fallback/` contains a bundled copy of typeshed stubs. This provides the Viper stdlib type stubs when no external typeshed is available.
**Localized diagnostics**: All user-facing diagnostic messages come from `localization/localize.ts`, not inline strings.
@@ -77,7 +77,7 @@ Source files are processed through these phases in order:
### Test Structure
Tests live in `packages/pyright-internal/src/tests/`. There are two main patterns:
Tests live in `packages/vipeye-internal/src/tests/`. There are two main patterns:
**Sample-based tests** (`typeEvaluator*.test.ts`, `checker.test.ts`):
- Each test calls `TestUtils.typeAnalyzeSampleFiles(['sampleName.py'])` to analyze a Viper file from `src/tests/samples/`.
@@ -96,7 +96,7 @@ Tests live in `packages/pyright-internal/src/tests/`. There are two main pattern
### Test Policy
Tests are the specification for Pyright behavior. Never modify tests just to make CI pass. Any change that makes types less precise (e.g., `T → Unknown`, `list[int] → list[Any]`, `Literal["x"] → str`) is a regression by default and requires explicit justification. See `.github/agents/pyright-test-policy.md` for details.
Tests are the specification for Vipeye behavior. Never modify tests just to make CI pass. Any change that makes types less precise (e.g., `T → Unknown`, `list[int] → list[Any]`, `Literal["x"] → str`) is a regression by default and requires explicit justification. See `.github/agents/vipeye-test-policy.md` for details.
## Code Style
+6 -6
View File
@@ -3,7 +3,7 @@ name: 'Build'
env:
NODE_VERSION: '22.x' # Shipped with VS Code.
ARTIFACT_NAME_VSIX: vsix
VSIX_NAME: vscode-pyright.vsix
VSIX_NAME: vscode-vipeye.vsix
on:
push:
@@ -12,7 +12,7 @@ on:
jobs:
build:
if: github.repository == 'microsoft/pyright'
if: github.repository == 'TermiNexus/Viper_VSCode'
runs-on: ubuntu-latest
name: Build
@@ -32,18 +32,18 @@ jobs:
- run: npm run install:all
- name: Build VSIX
working-directory: packages/vscode-pyright
working-directory: packages/vscode-vipeye
run: |
npm run package
mv pyright-*.vsix ${{ env.VSIX_NAME }}
mv vipeye-*.vsix ${{ env.VSIX_NAME }}
- uses: actions/upload-artifact@v4
with:
name: ${{ env.ARTIFACT_NAME_VSIX }}
path: packages/vscode-pyright/${{ env.VSIX_NAME }}
path: packages/vscode-vipeye/${{ env.VSIX_NAME }}
create_release:
if: github.repository == 'microsoft/pyright'
if: github.repository == 'TermiNexus/Viper_VSCode'
runs-on: ubuntu-latest
name: Create release
needs: [build]
+8 -8
View File
@@ -1,6 +1,6 @@
# This workflow runs mypy_primer, a tool that runs pyright on a variety
# of open-source Python projects that are known to type check with pyright.
# It builds pyright from the latest PR commit and the merge base of the PR
# This workflow runs mypy_primer, a tool that runs vipeye on a variety
# of open-source Python projects that are known to type check with vipeye.
# It builds vipeye from the latest PR commit and the merge base of the PR
# and compares the output of both. It uploads the diffs as an artifact and
# creates a PR comment with the results (with the help of the
# mypy_primer_comment action).
@@ -8,8 +8,8 @@
# This workflow definition borrows liberally from the mypy repo. The original
# workflow was designed to work in a sharded manner where n copies of
# mypy_primer are started in parallel. Each instance runs 1/n of the projects.
# For now, we run only one instance because pyright is fast, and the number
# of projects that use pyright for type checking is small. To change this in
# For now, we run only one instance because vipeye is fast, and the number
# of projects that use vipeye for type checking is small. To change this in
# the future, change the 'shard_index' matrix to [0, 1, ..., n-1] and set
# 'num-shards' to n.
@@ -22,9 +22,9 @@ on:
# Run on the creation or update of a PR.
pull_request:
paths:
- 'packages/pyright/**'
- 'packages/pyright-internal/src/**'
- 'packages/pyright-internal/typeshed-fallback/**'
- 'packages/vipeye/**'
- 'packages/vipeye-internal/src/**'
- 'packages/vipeye-internal/typeshed-fallback/**'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+6 -6
View File
@@ -1,6 +1,6 @@
# This workflow runs mypy_primer, a tool that runs pyright on a variety
# of open-source Python projects that are known to type check with pyright.
# It builds pyright from the latest commit and the last release tag and
# This workflow runs mypy_primer, a tool that runs vipeye on a variety
# of open-source Python projects that are known to type check with vipeye.
# It builds vipeye from the latest commit and the last release tag and
# compares the output of both. It uploads the diffs as an artifact.
name: Run mypy_primer on push
@@ -13,9 +13,9 @@ on:
branches:
- main
paths:
- 'packages/pyright/**'
- 'packages/pyright-internal/src/**'
- 'packages/pyright-internal/typeshed-fallback/**'
- 'packages/vipeye/**'
- 'packages/vipeye-internal/src/**'
- 'packages/vipeye-internal/typeshed-fallback/**'
# Also run manually if requested.
workflow_dispatch:
+9 -9
View File
@@ -14,7 +14,7 @@ on:
jobs:
typecheck:
if: github.repository == 'microsoft/pyright'
if: github.repository == 'TermiNexus/Viper_VSCode'
runs-on: ubuntu-latest
name: Typecheck
@@ -34,7 +34,7 @@ jobs:
- run: npx lerna exec --stream --no-bail -- "tsc --noEmit"
style:
if: github.repository == 'microsoft/pyright'
if: github.repository == 'TermiNexus/Viper_VSCode'
runs-on: ubuntu-latest
name: Style
@@ -79,9 +79,9 @@ jobs:
- run: npm run install:all
- name: npm test (pyright-internal)
- name: npm test (vipeye-internal)
run: npm test
working-directory: packages/pyright-internal
working-directory: packages/vipeye-internal
# Install python so we can create a VENV for tests
- name: Use Python ${{env.PYTHON_VERSION}}
@@ -117,13 +117,13 @@ jobs:
CI_IMPORT_TEST_VENVPATH: '../../'
CI_IMPORT_TEST_VENV: '.venv'
run: npm run test:imports
working-directory: packages/pyright-internal
working-directory: packages/vipeye-internal
- name: Run import tests with pythonpath
env:
CI_IMPORT_TEST_PYTHONPATH: ${{env.python_venv_path}}
run: npm run test:imports
working-directory: packages/pyright-internal
working-directory: packages/vipeye-internal
build:
runs-on: ubuntu-latest
@@ -145,13 +145,13 @@ jobs:
- uses: ./.github/actions/choose-npm-install
- run: npm publish --dry-run
working-directory: packages/pyright
working-directory: packages/vipeye
- run: npm publish --dry-run
working-directory: packages/pyright-typeserver
working-directory: packages/vipeye-typeserver
- run: npm run package
working-directory: packages/vscode-pyright
working-directory: packages/vscode-vipeye
required:
runs-on: ubuntu-latest
+1 -1
View File
@@ -133,7 +133,7 @@ serena/
AGENTS.md
# Generated benchmark output
packages/pyright-internal/src/tests/benchmarks/.generated/
packages/vipeye-internal/src/tests/benchmarks/.generated/
# perfCompare.py cached commit bundles
/build/perfCompare/
+1 -1
View File
@@ -142,7 +142,7 @@ serena/
AGENTS.md
# Generated benchmark output
packages/pyright-internal/src/tests/benchmarks/.generated/
packages/vipeye-internal/src/tests/benchmarks/.generated/
# perfCompare.py cached commit bundles
/build/perfCompare/
+10
View File
@@ -0,0 +1,10 @@
import stdio
import t, c
def add(a: int, b: int) -> int:
return a + b
def main() -> int:
stdio.printf("Hello, World!")
return 0
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Pyright - A static type checker for the Python language
Vipeye - A static type checker for the Viper language
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
+24 -23
View File
@@ -1,41 +1,42 @@
![Pyright](https://github.com/microsoft/pyright/blob/main/docs/img/PyrightLarge.png)
![Vipeye](docs/img/PyrightLarge.png)
# Static Type Checker for Viper
Pyright is a full-featured, standards-based static type checker for Viper. It is designed for high performance and can be used with large Viper source bases.
Vipeye is a full-featured, standards-based static type checker for Viper, written in TypeScript. It is designed for high performance and can be used with large Viper source bases.
Pyright includes both a [command-line tool](https://microsoft.github.io/pyright/#/command-line) and an [extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-pyright.pyright).
Vipeye includes both a [command-line tool](docs/command-line.md) and an [extension for Visual Studio Code](packages/vscode-vipeye). It is built on the Pyright codebase, adapted from the ground up to Viper semantics (AOT compilation, C-style types, pointer and memory semantics), and no longer type-checks Python.
## Packages
## Pyright Playground
- **`packages/vipeye-internal`** — Core analysis engine: parser, binder, type evaluator, checker, and language service. All logic lives here.
- **`packages/vipeye`** — CLI wrapper. Bundles `vipeye-internal` into a distributable npm package with `vipeye` and `vipeye-langserver` entry points.
- **`packages/vipeye-typeserver`** — Type server process for long-running editor sessions.
- **`packages/vscode-vipeye`** — VS Code extension client (Vipeye LSP), with the Viper core source (`packages/viper`) bundled at build time.
- **`packages/viper`** — Viper core source library: project (`.vpj`) management, toolchain, and the activity bar UI (Project / Toolchain / Settings).
Try Pyright in your browser using the [Pyright Playground](https://pyright-play.net/?code=MQAgKgFglgziMEMC2AHANgUxAEw0g9gHYwAuATgiRnBPgO4gDG%2BSBhIGZZ%2BZcjC7AEZZcVRlWzwSlKPzRoAniEFKUCslADmEEgDoAUPtwAzEAmzYAFAA8AXCGNp8lADQgF9x85IBKW-pBAkDIMEgBXMnZrEABqd0NQAAUEGBgoQk0zKTIQdNIBRiwUkBIILBgMZkJJBDJNMKQMQhJg6jC0Ejh0rLIw5qhGjmtClBIoIgNzKwBGNwAiOZ99IA).
## Key Differences from Pyright
- Viper dialect: `viperconfig.json` instead of `pyrightconfig.json`; config namespace `viper.*`.
- Viper stdlib stubs bundled in `vipeye-internal/vipershed-fallback`.
- Type semantics follow Viper rules: implicit conversions, pointer (`CPtr`/`CArray`), `t.CTypedef`/`t.CDefine`/`t.CEnum`, `T | t.CPtr` pointer folding, global-variable access rules, and more.
- Semantic highlighting and diagnostics are tailored to Viper syntax.
## Building and Testing
See [docs/build-debug.md](docs/build-debug.md).
## Documentation
Refer to [the documentation](https://microsoft.github.io/pyright) for installation, configuration, and usage details.
Refer to [the documentation](docs/README.md) for installation, configuration, and usage details.
## Environment variables
If Pyright fails to create a temporary directory (for example in remote/server environments where the OS temp directory doesn't exist or isn't writable), you can override the temp directory root:
If Vipeye fails to create a temporary directory (for example in remote/server environments where the OS temp directory doesn't exist or isn't writable), you can override the temp directory root:
- `PYRIGHT_TMPDIR`: Absolute path to a directory that Pyright can use for temporary files/directories. Pyright will create it if needed.
- `VIPEYE_TMPDIR`: Absolute path to a directory that Vipeye can use for temporary files/directories. Vipeye will create it if needed.
Pyright otherwise relies on the platform temp directory (for example `TMPDIR`, `TMP`, `TEMP`, or the OS default).
Vipeye otherwise relies on the platform temp directory (for example `TMPDIR`, `TMP`, `TEMP`, or the OS default).
## License
## Community
Do you have questions about Pyright or Viper type annotations in general? Post your questions in [the discussion section](https://github.com/microsoft/pyright/discussions).
If you would like to report a bug or request an enhancement, file a new issue in either the [pyright](https://github.com/microsoft/pyright/issues) or [pylance-release](https://github.com/microsoft/pylance-release/issues) issue tracker. In general, core type checking functionality is associated with Pyright while language service functionality is associated with Pylance, but the same contributors monitor both repos. For best results, provide the information requested in the issue template.
## Contributing
This project welcomes contributions and suggestions. For feature and complex bug fix contributions, it is recommended that you first discuss the proposed change with Pyright’s maintainers before submitting the pull request. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
MIT
-7
View File
@@ -1,7 +0,0 @@
{
"viper.analysis.extraPaths": [
"D:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes"
],
"viper.analysis.include": ["Test"],
"viper.analysis.diagnosticMode": "openFilesOnly"
}
View File
Whitespace-only changes.
-36
View File
@@ -1,36 +0,0 @@
import t, c
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
@c.Attribute(t.attr.packed)
class memory_map_entry:
type: t.CUnsignedInt
_pad: t.CUnsignedInt
physical_start: t.CUnsignedLong
virtual_start: t.CUnsignedLong
num_pages: t.CUnsignedLong
attribute: t.CUnsignedLong
class bootinfo:
MemmapAddr: t.CUnsignedLong
MemmapSize: t.CUnsignedLong
MemmapDescSize: t.CUnsignedLong
kernel_PhysAddr: t.CUnsignedLong
framebuffer_addr: t.CUnsignedLong
framebuffer_size: t.CUnsignedLong
framebuffer_width: t.CUnsignedLong
framebuffer_height: t.CUnsignedLong
framebuffer_pitch: t.CUnsignedLong
framebuffer_format: t.CUnsignedLong
system_table: t.CUnsignedLong
-346
View File
@@ -1,346 +0,0 @@
from stdint import *
import bootinfo
import intr
import platform.pch as pch
import platform.pch.timer as timer
import platform.pch.rtc as rtc
import drivers.serial.uart.su8250 as su8250
import drivers.serial.uart.serial as serial
import drivers.devfs.devfs as devfs
import paging.paging as paging
import drivers.video.vesafb.vga as vga
import drivers.video.vesafb.gfx as gfx
import drivers.storage.ide.ide as ide
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import mm.mm as mm
import string
import sched.sched as sched
import sched.process as proc
import drivers.input.keyboard.keyboard as keyboard
import drivers.input.mouse.mouse as mouse
import drivers.usb.usb as usb
import drivers.core.cpu.cpu as cpu
import drivers.core.cpu.apic as apic
import viperlib
import services.keyboard as kbd_svc
import services.mouse as mse_svc
import services.desktop as desktop
import intr.syscall as syscall
import execrunner.elf as elf
import t, c
import asm
kbd_tid: t.CInt = -1
mse_tid: t.CInt = -1
BootInfo: bootinfo.bootinfo | t.CPtr
@t.Object
# @t.CVTable
class ViperKernel:
BootInfo: bootinfo.bootinfo | t.CPtr
VGA: vga._VGAScreenDriver | t.CPtr
VGA_drv: vga._VGAScreenDriver
def __init__(self):
global BootInfo
self.BootInfo = BootInfo
BootInfo: bootinfo.bootinfo | t.CPtr = self.BootInfo
serial.init()
serial.puts("===== ViperOS VKernel Test\n =====")
serial.puts("V2.3.8\n")
intr.gdt.init()
# Set IA32_KERNEL_GS_BASE = &_per_cpu so swapgs in ISR/syscall works.
# _CPUObject is never instantiated, so __init_tss__ never runs;
# without this, GS base stays 0 and gs:[0] writes hit null -> triple fault.
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(cpu._per_cpu)))
serial.puts("[main] gdt init done\n")
intr.idt.init()
syscall.init()
serial.puts("[main] syscall init done\n")
# 必须在 sti() 之前初始化调度器,否则中断触发时 _sched_ptr 为 NULL 会导致三重故障
sched.Scheduler()
serial.puts("[main] sched init done\n")
timer.timer_init()
serial.puts("[main] timer init done\n")
#mouse.init()
#serial.puts("[main] mouse init done\n")
#apic.early_init()
#serial.puts("[main] apic init done\n")
asm.sti()
serial.puts("[main] sti done\n")
timer.timer_msleep(100)
serial.puts("[main] msleep done\n")
rtc.rtc_init()
serial.puts("[main] rtc init done\n")
ncpu: t.CUInt32T = apic.get_cpu_count()
ncpu_cr: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(ncpu_cr), 32, "[main] cpu_count=%u\n", ncpu)
serial.puts(ncpu_cr)
if ncpu > 1:
apic.start_aps()
serial.puts("[main] kernel init done\n")
fb: t.CVoid | t.CPtr = BootInfo.framebuffer_addr
width: t.CUInt64T = BootInfo.framebuffer_width
height: t.CUInt64T = BootInfo.framebuffer_height
pitch: t.CUInt64T = BootInfo.framebuffer_pitch
fb_format: t.CUInt64T = BootInfo.framebuffer_format
fb_size: t.CUInt64T = BootInfo.framebuffer_size
if BootInfo is not None:
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
fb_pages: t.CUInt64T = (fb_size + t.CUInt64T(0xFFF)) >> t.CUInt64T(12)
fpi: t.CUInt64T = 0
while fpi < fb_pages:
fva: t.CUInt64T = t.CUInt64T(fb) + fpi * t.CUInt64T(0x1000)
paging.MapPage(fva, fva, paging.PTE_WRITABLE | paging.PTE_PCD)
fpi += 1
mm.init(BootInfo.MemmapAddr, BootInfo.MemmapSize, BootInfo.MemmapDescSize, BootInfo.framebuffer_addr, fb_size)
pt_pool_buf: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf, t.CUInt64T(513) * t.CUInt64T(4096))
else:
paging.init(0, 0)
mm.init(0, 0, 0, 0, 0)
pt_pool_buf2: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf2, t.CUInt64T(513) * t.CUInt64T(4096))
serial.puts("[main] paging and mm init done\n")
proc.ProcessManager()
serial.puts("[main] process manager init done\n")
ide.init()
serial.puts("[main] ide init done\n")
serial.puts("[main] initializing FAT32 filesystem\n")
scan_res: t.CInt = fat32.scan_drives()
ndrives: t.CInt = fat32.get_drive_count()
ndrives_cr: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(ndrives_cr), 64, "[fat32] scan_res=%d found %d drives\n", scan_res, ndrives)
serial.puts(ndrives_cr)
if ndrives > 0:
mount_res: t.CInt = fat32.mount()
if mount_res == 0:
dp: fat32_types.dirobj
res: t.CInt = fat32.opendir("/", c.Addr(dp))
if res == 0:
serial.puts("[fat32] listing 0:/\n")
count: t.CInt = 0
while count < 20:
info: fat32_types.fileinfo
res2: t.CInt = fat32.readdir(c.Addr(dp), c.Addr(info))
if res2 != 0: break
if info.fname[0] == 0: break
is_dir: t.CInt = 1 if (info.attr & fat32_types.AM_DIR) else 0
entry_cr: t.CArray[t.CChar, 300]
viperlib.snprintf(c.Addr(entry_cr), 300, " %s size=%lu dir=%d\n", c.Addr(info.fname[0]), info.file_size, is_dir)
serial.puts(entry_cr)
count = count + 1
fat32.closedir(c.Addr(dp))
serial.puts("[fat32] directory listing done\n")
else:
serial.puts("[fat32] failed to open root directory\n")
# Load ELF apps BEFORE running destructive FAT32 tests
serial.puts("[main] loading ELF apps...\n")
dp_apps: fat32_types.dirobj
apps_res: t.CInt = fat32.opendir("/APPS", c.Addr(dp_apps))
if apps_res == 0:
serial.puts("[main] APPS dir listing:\n")
ac: t.CInt = 0
while ac < 20:
ai: fat32_types.fileinfo
ar: t.CInt = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
if ar != 0: break
if ai.fname[0] == 0: break
ae: t.CArray[t.CChar, 300]
viperlib.snprintf(c.Addr(ae), 300, " %s size=%lu\n", c.Addr(ai.fname[0]), ai.file_size)
serial.puts(ae)
ac = ac + 1
fat32.closedir(c.Addr(dp_apps))
else:
serial.puts("[main] APPS dir not found\n")
sched.Scheduler.disable()
hello_pid: t.CInt = elf.spawn_elf("/APPS/hello.elf")
if hello_pid < 0:
serial.puts("[main] Hello spawn failed\n")
else:
slog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(slog), 64, "[main] Hello spawned as pid=%d\n", hello_pid)
serial.puts(slog)
term_pid: t.CInt = elf.spawn_elf("/APPS/terminal.elf")
if term_pid < 0:
serial.puts("[main] Terminal spawn failed\n")
else:
tlog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(tlog), 64, "[main] Terminal spawned as pid=%d\n", term_pid)
serial.puts(tlog)
garg_pid: t.CInt = elf.spawn_elf("/APPS/gargantua.elf")
if garg_pid < 0:
serial.puts("[main] Gargantua spawn failed\n")
else:
glog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(glog), 64, "[main] Gargantua spawned as pid=%d\n", garg_pid)
serial.puts(glog)
s3d_pid: t.CInt = elf.spawn_elf("/APPS/scene3d.elf")
if s3d_pid < 0:
serial.puts("[main] Scene3D spawn failed\n")
else:
s3d_log: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(s3d_log), 64, "[main] Scene3D spawned as pid=%d\n", s3d_pid)
serial.puts(s3d_log)
so_base: t.CVoid | t.CPtr = elf.load_so("/LIBS/SLOG.SO")
if so_base is not None:
serial.puts("[main] slog.so loaded, calling log_info...\n")
log_info_fn: t.CVoid | t.CPtr = elf.get_so_symbol(so_base, "log_info", "/LIBS/SLOG.SO")
if log_info_fn is not None:
msg: t.CConst | t.CChar | t.CPtr = "Hello from shared library!"
c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
else:
serial.puts("[main] log_info symbol not found\n")
else:
serial.puts("[main] failed to load slog.so\n")
sched.Scheduler.enable()
# FAT32 destructive tests removed to prevent disk.img corruption
# (write/rename/delete/mkdir/rmdir permanently modify the disk image)
fat32.unmount()
serial.puts("[fat32] unmounted\n")
else:
serial.puts("[fat32] mount failed\n")
else:
serial.puts("[fat32] no drives found\n")
devfs.devfs_init()
devfs.devfs_register_serial0()
devfs.devfs_register_serial1()
devfs.devfs_register_keyboard()
devfs.devfs_register_mouse()
serial.puts("[main] sched started\n")
fd: t.CInt = devfs.devfs_open("/dev/serial0", 0)
buf: t.CArray[t.CChar, 64]
string.memset(c.Addr(buf), 0, 64)
devfs.devfs_write(fd, "hello from devfs!", 17)
devfs.devfs_read(fd, c.Addr(buf), 64)
devfs.devfs_close(fd)
cr: t.CArray[t.CChar, 30]
string.memset(c.Addr(cr), 0, 30)
viperlib.snprintf(c.Addr(cr), 30, "hello %d %.2f", 42, float(0.24))
serial.puts(cr)
serial.puts("\n")
bootinfo_cr: t.CArray[t.CChar, 256]
string.memset(c.Addr(bootinfo_cr), 0, 256)
viperlib.snprintf(c.Addr(bootinfo_cr), 256, "Bootinfo 0x%016lx %lu %lu %lu %lu %lu map 0x%lx+%lu descsize=%lu",
BootInfo.framebuffer_addr,
BootInfo.framebuffer_format,
BootInfo.framebuffer_width,
BootInfo.framebuffer_height,
BootInfo.framebuffer_pitch,
BootInfo.framebuffer_size,
BootInfo.MemmapAddr,
BootInfo.MemmapSize,
BootInfo.MemmapDescSize)
serial.puts(bootinfo_cr)
serial.puts("\n")
a: t.CConst | str = "Hello"
serial.putchar(a[4]) # o
serial.puts("\n")
d: t.CConst | int = 42
b: t.CConst | int | t.CPtr = c.Addr(d)
string.memset(c.Addr(cr), 0, 4)
viperlib.snprintf(c.Addr(cr), 30, "%d", b[0]) # 42
serial.puts(cr)
serial.puts("\n")
# paging and mm already initialized before FAT32
usb.init()
serial.puts("[main] starting keyboard service\n")
kbd_svc.start()
serial.puts("[main] starting mouse service\n")
mse_svc.start()
serial.puts("[main] services started\n")
self.VGA_drv = vga._VGAScreenDriver(fb, width, height, pitch, fb_format)
self.VGA = c.Addr(self.VGA_drv)
self.VGA.Print(100, 100, "ViperOS VKernel Test")
serial.puts("你好\n")
serial.puts("[main] starting desktop\n")
desktop.start(fb, width, height, pitch)
serial.puts("[main] desktop started\n")
# ELF apps already loaded before FAT32 tests
serial.puts("[main] entering main loop\n")
# sched.sched_dump()
last_sec: t.CUInt32T = 0
loop_cnt: t.CUInt32T = 0
while True:
cur_sec: t.CUInt32T = timer.timer_get_seconds()
if cur_sec != last_sec:
last_sec = cur_sec
#if cur_sec % 5 == 0:
# sched.sched_dump()
loop_cnt += 1
sched.Scheduler._yield()
#while True:
# cube.RenderScene(back_fb, cube.SCREEN_W, cube.SCREEN_H, time)
# string.memcpy(fb, back_fb, width * height * 4)
# serial.puts("time")
# time += float(0.1)
# circle(width / 2, height / 2, 180, fb)
# circle(640, 400, 180, 0xFFFFFFFF)
# X 字符串遍历
# c.Cast 更换
# 时钟
# PCI
# SHA1 它者文件更新
# assets
# X attributes语法和谐
# 合成式类型转换
VKP: ViperKernel | t.CPtr
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt:
global VKP, BootInfo
saved_rdi: t.CUnsignedLong
c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi",
op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI])
asm.BSSClean()
BootInfo = saved_rdi # 隐式转为 bootinfo*
VKP = c.Addr(ViperKernel())
while True:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
return 0
-16
View File
@@ -1,16 +0,0 @@
# 测试字符串注解(前向引用)的循环依赖支持
# 期望:k: 'a' 能正确解析为类 a 自身类型
class a:
k: 'a' # 字符串注解,引用类自身(循环依赖)
next: 'a | None' # 字符串注解中的类型组合
class Node:
value: int
next: 'Node' # 链表节点的循环引用
# 测试:实例化后访问字段
def test() -> int:
n: Node = Node()
n.value = 42
return n.value
-24
View File
@@ -1,24 +0,0 @@
{
global:
isr0_handler;
isr1_handler;
isr2_handler;
isr3_handler;
isr4_handler;
isr5_handler;
isr6_handler;
isr7_handler;
isr8_handler;
isr9_handler;
isr10_handler;
isr11_handler;
isr12_handler;
isr13_handler;
isr14_handler;
isr15_handler;
isr16_handler;
isr17_handler;
isr18_handler;
isr19_handler;
local: *;
};
-39
View File
@@ -1,39 +0,0 @@
ENTRY(_start)
SECTIONS {
. = 0x100000;
.text : {
*(.text.startup)
*(.text)
*(.text.*)
}
.rodata : {
*(.rodata)
*(.rodata.*)
}
.data : {
*(.data)
*(.data.*)
}
.bss : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(COMMON)
__bss_end = .;
}
/DISCARD/ : {
*(.comment)
*(.note)
*(.eh_frame)
*(.eh_frame_hdr)
*(.reloc)
*(.rela)
*(.debug*)
}
}
-30
View File
@@ -1,30 +0,0 @@
{
"name": "Kernel",
"version": "1.0.0",
"source_dir": "./Kernel",
"build_dir": "./.tpv_build",
"compiler": {
"cmd": "llc",
"flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"]
},
"linker": {
"cmd": "ld.lld.exe",
"flags": [
"-m", "elf_x86_64",
"-T", "linker.ld",
"--oformat", "binary",
"--strip-all"
],
"output": "kernel.bin"
},
"includes": ["../../TransPyC/includes"],
"target": {
"triple": "x86_64-none-elf",
"datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
},
"options": {
"slice_level": 3,
"target": "llvm",
"strict_mode": true
}
}
-29
View File
@@ -1,29 +0,0 @@
path = r'd:\Users\TermiNexus\Desktop\Viper_VSCode\packages\vipeye-internal\src\analyzer\types.ts'
with open(path, 'r', encoding='utf-8') as f:
text = f.read()
old1 = (
"// Viper \u6269\u5c55\uff1aViper C \u6d6e\u70b9\u7c7b\u578b\u540d\u79f0\u767d\u540d\u5355\u3002\n"
"const _viperCFloatTypeNames = new Set<string>([\n"
" 'CFloat', 'CDouble', 'CFloat8T', 'CFloat16T', 'CFloat32T', 'CFloat64T', 'CFloat128T',\n"
"]);\n"
)
new1 = old1 + (
"\n"
"// Viper \u6269\u5c55\uff1a\u5224\u65ad\u7c7b\u578b\u540d\u662f\u5426\u4e3a Viper C \u6d6e\u70b9\u7c7b\u578b\u3002\n"
"// \u7528\u4e8e\u534f\u8bae\u5339\u914d\u7b49\u573a\u666f\uff0c\u8ba9 CType \u6d6e\u70b9\u5b50\u7c7b\u6ee1\u8db3 SupportsFloat \u7b49\u6570\u503c\u534f\u8bae\u3002\n"
"export function isViperCFloatTypeName(name: string): boolean {\n"
" return _viperCFloatTypeNames.has(name);\n"
"}\n"
)
c1 = text.count(old1)
print('Edit1 match count:', c1)
assert c1 == 1, f'Edit1 match count: {c1}'
text = text.replace(old1, new1)
with open(path, 'w', encoding='utf-8') as f:
f.write(text)
print('isViperCFloatTypeName function added.')
+18
View File
@@ -0,0 +1,18 @@
from openai import OpenAI
# 指向本地Ollama服务,不是OpenAI官网
client = OpenAI(
base_url="http://127.0.0.1:11434/v1",
api_key="dummy" # 本地模式key无校验,随便填写占位字符串
)
resp = client.chat.completions.create(
model="qwen3.5:4b",
messages=[
{"role":"user","content":"你好"}
],
max_tokens=1024,
temperature=0.7
)
print(resp.choices[0].message.content)
+27 -27
View File
@@ -10,15 +10,15 @@ resources:
ref: refs/tags/release
variables:
- name: TeamName
value: Pyright
value: Vipeye
- name: VSIX_NAME
value: vscode-pyright.vsix
value: vscode-vipeye.vsix
- name: ARTIFACT_NAME_VSIX
value: vsix
- name: PACKAGE_NAME
value: pyright.tgz
value: vipeye.tgz
- name: ARTIFACT_NAME_PACKAGE
value: pyright
value: vipeye
- name: AZURE_ARTIFACTS_FEED
value: 'https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/Pylance_PublicPackages/npm/registry/'
@@ -28,11 +28,11 @@ extends:
sdl:
codeSignValidation:
enabled: true
additionalTargetsGlobPattern: -|**/gdn-vscode-pyright.vsix/**
additionalTargetsGlobPattern: -|**/gdn-vscode-vipeye.vsix/**
codeql:
compiled:
enabled: false
justificationForDisabling: 'Running a scan on the Pyright-Build azure-pipelines.yml'
justificationForDisabling: 'Running a scan on the Vipeye-Build azure-pipelines.yml'
sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
pool:
name: AzurePipelines-EO
@@ -81,19 +81,19 @@ extends:
inputs:
script: |
npm run package
workingDirectory: packages/vscode-pyright
workingDirectory: packages/vscode-vipeye
- task: PowerShell@2
inputs:
targetType: 'inline'
script: 'Move-Item -Path "pyright-*.vsix" -Destination "$(VSIX_NAME)"'
workingDirectory: packages/vscode-pyright
script: 'Move-Item -Path "vipeye-*.vsix" -Destination "$(VSIX_NAME)"'
workingDirectory: packages/vscode-vipeye
displayName: 'Move VSIX file'
- task: CopyFiles@2
displayName: 'Copy vsix to: build_output'
inputs:
SourceFolder: packages/vscode-pyright
SourceFolder: packages/vscode-vipeye
Contents: '$(VSIX_NAME)'
TargetFolder: build_output
@@ -103,7 +103,7 @@ extends:
- script: npx vsce generate-manifest -i $(VSIX_NAME) -o extension.manifest
displayName: 'Generate extension manifest'
workingDirectory: packages/vscode-pyright
workingDirectory: packages/vscode-vipeye
- task: NuGetToolInstaller@1
displayName: 'Install NuGet'
@@ -111,13 +111,13 @@ extends:
- task: NuGetCommand@2
inputs:
command: 'restore'
restoreSolution: '$(Build.SourcesDirectory)/packages/vscode-pyright/packages.config'
restoreDirectory: '$(Build.SourcesDirectory)/packages/vscode-pyright/packages'
restoreSolution: '$(Build.SourcesDirectory)/packages/vscode-vipeye/packages.config'
restoreDirectory: '$(Build.SourcesDirectory)/packages/vscode-vipeye/packages'
- task: MSBuild@1
displayName: 'Sign binaries'
inputs:
solution: 'packages/vscode-pyright/sign.proj'
solution: 'packages/vscode-vipeye/sign.proj'
msbuildArguments: '/verbosity:diagnostic /p:SignType=real'
- task: PowerShell@2
@@ -125,8 +125,8 @@ extends:
inputs:
targetType: 'inline'
script: |
$manifestPath = "$(Build.SourcesDirectory)\packages\vscode-pyright\extension.manifest"
$signaturePath = "$(Build.SourcesDirectory)\packages\vscode-pyright\extension.signature.p7s"
$manifestPath = "$(Build.SourcesDirectory)\packages\vscode-vipeye\extension.manifest"
$signaturePath = "$(Build.SourcesDirectory)\packages\vscode-vipeye\extension.signature.p7s"
$compareResult = Compare-Object (Get-Content $manifestPath) (Get-Content $signaturePath)
if ($compareResult -eq $null) {
Write-Error "Files are identical. Failing the build."
@@ -138,14 +138,14 @@ extends:
- task: CopyFiles@2
displayName: 'Copy extension.manifest'
inputs:
SourceFolder: 'packages/vscode-pyright'
SourceFolder: 'packages/vscode-vipeye'
Contents: 'extension.manifest'
TargetFolder: build_output
- task: CopyFiles@2
displayName: 'Copy extension.signature.p7s'
inputs:
SourceFolder: 'packages/vscode-pyright'
SourceFolder: 'packages/vscode-vipeye'
Contents: 'extension.signature.p7s'
TargetFolder: build_output
@@ -179,18 +179,18 @@ extends:
- script: npm pack
displayName: npm pack
workingDirectory: packages/pyright
workingDirectory: packages/vipeye
- script: mv pyright-*.tgz ${{ variables.PACKAGE_NAME }}
- script: mv vipeye-*.tgz ${{ variables.PACKAGE_NAME }}
displayName: Remove version from package name
workingDirectory: packages/pyright
workingDirectory: packages/vipeye
# CredScan does not understand scanning a single file. So, it will default to scanning the whole folder that your output is pointing to.
# We don't want it to scan the microbuild plugins, which is installed in the agent.stagedirectory by default.
- task: CopyFiles@2
displayName: 'Copy ${{ variables.PACKAGE_NAME }} to subfolder'
inputs:
SourceFolder: packages/pyright
SourceFolder: packages/vipeye
Contents: '${{ variables.PACKAGE_NAME }}'
TargetFolder: '$(Build.ArtifactStagingDirectory)/${{ variables.ARTIFACT_NAME_PACKAGE }}'
@@ -215,17 +215,17 @@ extends:
- checkout: none
# Next step fails the build if https://github.com/microsoft/pyright/issues/10350 repros.
- script: |
mkdir pyrightTest
cd pyrightTest
mkdir vipeyeTest
cd vipeyeTest
yarn
yarn add --dev $(Pipeline.Workspace)/$(ARTIFACT_NAME_PACKAGE)/$(PACKAGE_NAME)
node_modules/.bin/pyright --version
node_modules/.bin/vipeye --version
displayName: Validate npm package
- task: GitHubRelease@1 #https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/github-release-v1?view=azure-pipelines
displayName: 'Create GitHub Release'
inputs:
gitHubConnection: 'Github-Pylance' # The name of the GitHub service connection
repositoryName: 'microsoft/pyright' # The name of your GitHub repository
repositoryName: 'TermiNexus/Viper_VSCode' # The name of your GitHub repository
action: 'create'
isDraft: true
isPreRelease: false
@@ -251,7 +251,7 @@ extends:
timeoutInMinutes: 120 # task times out in 2 hours
inputs:
notifyUsers: '[DevDiv]\Python.Language Server,eric@traut.com'
instructions: 'In the next 2 hours please test the latest draft release of Pyright, then Publish the release in GitHub.'
instructions: 'In the next 2 hours please test the latest draft release of Vipeye, then Publish the release in GitHub.'
onTimeout: 'reject' # require sign-off
- stage: PublishToMarketplace
+3 -3
View File
@@ -9,7 +9,7 @@ variables:
- name: SigningType
value: 'real'
- name: TeamName
value: Pyright
value: Vipeye
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
@@ -53,10 +53,10 @@ extends:
inputs:
script: |
npm run package
workingDirectory: packages/vscode-pyright
workingDirectory: packages/vscode-vipeye
- task: CopyFiles@2
displayName: 'Copy vsix to: build_output'
inputs:
SourceFolder: packages/vscode-pyright
SourceFolder: packages/vscode-vipeye
Contents: '*.vsix'
TargetFolder: build_output
+1 -1
View File
@@ -181,7 +181,7 @@ path = downloadUnicodeData(unicodeVersion)
chars = parseFile(path)
surrogateRanges = getSurrogateRanges(chars)
with open("packages/pyright-internal/src/parser/unicode.ts", "w") as writer:
with open("packages/vipeye-internal/src/parser/unicode.ts", "w") as writer:
writer.write(
f"""/*
* unicode.ts
+24 -24
View File
@@ -4,32 +4,32 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
#
# Benchmarks pyright's type-checking performance across two or more git
# Benchmarks vipeye's type-checking performance across two or more git
# commits/branches by building the production CLI bundle at each commit and
# timing repeated runs over a fixed corpus. See the module docstring for usage
# and the measurement methodology.
"""Compare pyright type-checking performance across two or more commits/branches.
"""Compare vipeye type-checking performance across two or more commits/branches.
Adapted from mypy's misc/perf_compare.py for pyright. Where mypy self-checks its
own (mypyc-compiled) source, pyright is a bundled JS CLI, so this script:
Adapted from mypy's misc/perf_compare.py for vipeye. Where mypy self-checks its
own (mypyc-compiled) source, vipeye is a bundled JS CLI, so this script:
* For each target commit: checks it out *in place*, builds the production CLI
bundle (``packages/pyright/dist``), and stashes that dist dir under
bundle (``packages/vipeye/dist``), and stashes that dist dir under
``build/perfCompare/binaries/<sha>/`` so later runs can skip the rebuild.
* Restores your original branch/commit when the build phase is done.
* Runs each commit's bundle N times over a fixed corpus, in randomized
interleaved order, parsing pyright's own ``Completed in X.XXXsec`` line as the
interleaved order, parsing vipeye's own ``Completed in X.XXXsec`` line as the
per-run metric (in-process analysis time -- excludes node startup jitter).
* Reports per-commit mean/median plus robust paired deltas vs the baseline.
Usage:
python build/perfCompare.py --corpus <path-to-python-project> main HEAD
python build/perfCompare.py --corpus <path-to-project> main HEAD
Requirements / caveats:
* Run from the pyright repo root with a CLEAN working tree (it checks out
* Run from the vipeye repo root with a CLEAN working tree (it checks out
commits in place, reusing the already-installed node_modules -- worktrees
would lack them).
* The corpus path is whatever you want type-checked; it stays fixed across all
@@ -51,8 +51,8 @@ import time
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT = os.path.dirname(SCRIPT_DIR)
PYRIGHT_PKG = os.path.join(REPO_ROOT, "packages", "pyright")
DIST_DIR = os.path.join(PYRIGHT_PKG, "dist")
VIPEYE_PKG = os.path.join(REPO_ROOT, "packages", "vipeye")
DIST_DIR = os.path.join(VIPEYE_PKG, "dist")
# Cached production bundles, keyed by commit SHA, kept beside this script (gitignored).
BUILD_CACHE = os.path.join(SCRIPT_DIR, "perfCompare", "binaries")
@@ -91,13 +91,13 @@ def working_tree_clean() -> bool:
def build_commit(commit: str, sha: str) -> str:
"""Check out `commit`, build the prod bundle, cache dist under the SHA. Returns cache dir."""
cache_dir = os.path.join(BUILD_CACHE, sha)
if os.path.isdir(cache_dir) and os.path.isfile(os.path.join(cache_dir, "pyright.js")):
if os.path.isdir(cache_dir) and os.path.isfile(os.path.join(cache_dir, "vipeye.js")):
print(f"build cache hit for {commit} ({sha[:10]}): {cache_dir}")
return cache_dir
heading(f"Building {commit} ({sha[:10]})")
git("checkout", "-q", sha)
subprocess.run(["npm", "run", "build"], cwd=PYRIGHT_PKG, check=True)
subprocess.run(["npm", "run", "build"], cwd=VIPEYE_PKG, check=True)
if os.path.isdir(cache_dir):
shutil.rmtree(cache_dir)
@@ -108,15 +108,15 @@ def build_commit(commit: str, sha: str) -> str:
def run_once(bundle_dir: str, corpus: str) -> tuple[float, float | None, float]:
"""Run pyright on corpus once; return (wall_completed_sec, check_sec | None, cpu_sec).
"""Run vipeye on corpus once; return (wall_completed_sec, check_sec | None, cpu_sec).
`wall` is pyright's own ``Completed in`` (in-process analysis wall time). `cpu` is the
`wall` is vipeye's own ``Completed in`` (in-process analysis wall time). `cpu` is the
user+sys CPU time of the node child, via the RUSAGE_CHILDREN delta around the run --
much less sensitive to scheduling/background noise. This is accurate because pyright runs
much less sensitive to scheduling/background noise. This is accurate because vipeye runs
single-process by default (no ``--threads``), so there are no un-reaped worker processes
whose CPU would escape node's accounting.
"""
cmd = ["node", os.path.join(bundle_dir, "pyright.js"), "--stats", os.path.abspath(corpus)]
cmd = ["node", os.path.join(bundle_dir, "vipeye.js"), "--stats", os.path.abspath(corpus)]
r0 = resource.getrusage(resource.RUSAGE_CHILDREN)
# Ignore exit code: corpora routinely produce type errors.
res = subprocess.run(cmd, cwd=REPO_ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@@ -125,7 +125,7 @@ def run_once(bundle_dir: str, corpus: str) -> tuple[float, float | None, float]:
m = COMPLETED_RE.search(res.stdout)
if not m:
sys.stderr.write(res.stdout[-2000:] + "\n")
raise RuntimeError("Could not parse 'Completed in ...sec' from pyright output")
raise RuntimeError("Could not parse 'Completed in ...sec' from vipeye output")
c = CHECK_RE.search(res.stdout)
return float(m.group(1)), (float(c.group(1)) if c else None), cpu
@@ -153,17 +153,17 @@ def main() -> None:
formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__
)
src = p.add_mutually_exclusive_group(required=True)
src.add_argument("--corpus", help="path to a Python project *directory* to type-check (fixed across commits)")
src.add_argument("--corpus-file", help="path to a single Python *file* to type-check (e.g. one hot file). "
src.add_argument("--corpus", help="path to a project *directory* to type-check (fixed across commits)")
src.add_argument("--corpus-file", help="path to a single *file* to type-check (e.g. one hot file). "
"Lower per-run cost and variance than a whole project.")
p.add_argument("--num-runs", type=int, default=10, help="measured runs per commit (default 10)")
p.add_argument("--warmup-runs", type=int, default=2, help="leading warmup runs to discard (default 2)")
p.add_argument("--metric", choices=["wall", "cpu"], default="wall",
help="quantity to compare: 'wall' (pyright's reported analysis time, default) or "
help="quantity to compare: 'wall' (vipeye's reported analysis time, default) or "
"'cpu' (user+sys CPU of the node child). 'cpu' is far less sensitive to background "
"interference/scheduling, tightening the distribution -- recommended for high run counts.")
p.add_argument("--workers1", action="store_true",
help="parity flag with mypy's perf_compare: assert single-process analysis. Pyright already "
help="parity flag with mypy's perf_compare: assert single-process analysis. Vipeye already "
"runs single-process by default (multi-process needs --threads, which this script never "
"passes), so this is the default; the flag is accepted to document intent.")
p.add_argument("--no-build", action="store_true", help="skip building; reuse cached dist bundles under build/perfCompare/binaries/")
@@ -171,7 +171,7 @@ def main() -> None:
args = p.parse_args()
if not os.path.isdir(os.path.join(REPO_ROOT, ".git")):
sys.exit("error: run from the pyright repo root")
sys.exit("error: run from the vipeye repo root")
corpus = args.corpus if args.corpus is not None else args.corpus_file
if args.corpus is not None and not os.path.isdir(args.corpus):
sys.exit(f"error: --corpus directory not found: {args.corpus}")
@@ -185,7 +185,7 @@ def main() -> None:
if args.no_build:
for c in commits:
cache_dir = os.path.join(BUILD_CACHE, shas[c])
if not os.path.isfile(os.path.join(cache_dir, "pyright.js")):
if not os.path.isfile(os.path.join(cache_dir, "vipeye.js")):
sys.exit(f"error: --no-build but no cached bundle for {c} ({shas[c][:10]})")
bundles[c] = cache_dir
else:
@@ -201,7 +201,7 @@ def main() -> None:
git("checkout", "-q", original)
num_runs = args.num_runs + args.warmup_runs
metric_label = "CPU time (user+sys)" if args.metric == "cpu" else "pyright-reported wall time"
metric_label = "CPU time (user+sys)" if args.metric == "cpu" else "vipeye-reported wall time"
heading(f"Measuring (corpus: {corpus}, {args.num_runs} runs + {args.warmup_runs} warmup, "
f"metric: {args.metric}, single-process)")
# `results` holds the chosen comparison metric; the other values are still printed per run.
+3 -3
View File
@@ -5,12 +5,12 @@ steps:
- task: npmAuthenticate@0
inputs:
workingFile: packages/pyright/.npmrc
workingFile: packages/vipeye/.npmrc
- task: npmAuthenticate@0
inputs:
workingFile: packages/pyright-internal/.npmrc
workingFile: packages/vipeye-internal/.npmrc
- task: npmAuthenticate@0
inputs:
workingFile: packages/vscode-pyright/.npmrc
workingFile: packages/vscode-vipeye/.npmrc
+1 -1
View File
@@ -27,7 +27,7 @@ def get_script_dir() -> Path:
def get_typeshed_fallback_dir() -> Path:
"""Get the path to the typeshed-fallback directory."""
script_dir = get_script_dir()
return script_dir.parent / "packages" / "pyright-internal" / "typeshed-fallback"
return script_dir.parent / "packages" / "vipeye-internal" / "typeshed-fallback"
def run_git_command(args: list[str], cwd: Path) -> subprocess.CompletedProcess:
+3 -3
View File
@@ -1,9 +1,9 @@
![Pyright](img/PyrightLarge.png)
![Vipeye](img/PyrightLarge.png)
# Static type checker for Viper
Pyright is a full-featured, [standards-compliant](https://htmlpreview.github.io/?https://github.com/viper/typing/blob/main/conformance/results/results.html) static type checker for Viper. It is designed for high performance and can be used with large Viper source bases.
Vipeye is a full-featured, [standards-compliant](https://htmlpreview.github.io/?https://github.com/viper/typing/blob/main/conformance/results/results.html) static type checker for Viper. It is designed for high performance and can be used with large Viper source bases.
Pyright includes a [command-line tool](command-line.md), a language server, and an [extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-pyright.pyright).
Vipeye includes a [command-line tool](command-line.md), a language server, and an [extension for Visual Studio Code](../packages/vscode-vipeye).
+1 -1
View File
@@ -1 +1 @@
[GitHub Site](https://github.com/Microsoft/pyright)
[GitHub Site](https://github.com/TermiNexus/Viper_VSCode)
+3 -3
View File
@@ -1,6 +1,6 @@
- Getting Started
- [Installing Pyright](installation.md)
- [Installing Vipeye](installation.md)
- [Getting Started](getting-started.md)
- [Static Typing](type-concepts.md)
- [Features](features.md)
@@ -11,7 +11,7 @@
- [Configuration Options](configuration.md#main-configuration-options)
- [Diagnostic Rules](configuration.md#type-check-diagnostics-settings)
- [Execution Environments](configuration.md#execution-environment-options)
- [Sample pyrightconfig.json](configuration.md#sample-config-file)
- [Sample viperconfig.json](configuration.md#sample-config-file)
- [Sample pyproject.toml](configuration.md#sample-pyprojecttoml-file)
- [Diagnostic Settings Defaults](configuration.md#diagnostic-settings-defaults)
- [Locale Configuration](configuration.md#locale-configuration)
@@ -36,6 +36,6 @@
- Development
- [Building & Debugging](build-debug.md)
- [Pyright Internals](internals.md)
- [Vipeye Internals](internals.md)
+10 -10
View File
@@ -1,4 +1,4 @@
## Building Pyright
## Building Vipeye
To install the dependencies for all packages in the repo:
1. Install [nodejs](https://nodejs.org/en/) version 16.x
@@ -8,7 +8,7 @@ To install the dependencies for all packages in the repo:
## Building the CLI
1. cd to the `packages/pyright` directory
1. cd to the `packages/vipeye` directory
2. Execute `npm run build`
Once built, you can run the command-line tool by executing the following:
@@ -17,23 +17,23 @@ Once built, you can run the command-line tool by executing the following:
## Building the VS Code extension
1. cd to the `packages/vscode-pyright` directory
1. cd to the `packages/vscode-vipeye` directory
2. Execute `npm run package`
The resulting package (pyright-X.Y.Z.vsix) can be found in the client directory.
The resulting package (vipeye-X.Y.Z.vsix) can be found in the client directory.
To install in VS Code, go to the extensions panel and choose “Install from VSIX...” from the menu, then select the package.
## Running Pyright tests
## Running Vipeye tests
1. cd to the `packages/pyright-internal` directory
1. cd to the `packages/vipeye-internal` directory
2. Execute `npm run test`
## Debugging Pyright
## Debugging Vipeye
To debug pyright, open the root source directory within VS Code. Open the debug sub-panel and choose “Pyright CLI” from the debug target menu. Click on the green “run” icon or press F5 to build and launch the command-line version in the VS Code debugger. There's also a similar option that provides a slightly faster build/debug loop: make sure you've built the pyright-internal project e.g. with Terminal > Run Build Task > tsc: watch, then choose “Pyright CLI (pyright-internal)”.
To debug vipeye, open the root source directory within VS Code. Open the debug sub-panel and choose “Vipeye CLI” from the debug target menu. Click on the green “run” icon or press F5 to build and launch the command-line version in the VS Code debugger. There's also a similar option that provides a slightly faster build/debug loop: make sure you've built the vipeye-internal project e.g. with Terminal > Run Build Task > tsc: watch, then choose “Vipeye CLI (Vipeye-internal)”.
To debug the VS Code extension, select “Pyright extension” from the debug target menu. Click on the green “run” icon or press F5 to build and launch a second copy of VS Code with the extension. Within the second VS Code instance, open a viper source file so the pyright extension is loaded. Return to the first instance of VS Code and select “Pyright extension attach server” from the debug target menu and click the green “run” icon. This will attach the debugger to the process that hosts the type checker. You can now set breakpoints, etc.
To debug the VS Code extension, select “Vipeye extension” from the debug target menu. Click on the green “run” icon or press F5 to build and launch a second copy of VS Code with the extension. Within the second VS Code instance, open a viper source file so the vipeye extension is loaded. Return to the first instance of VS Code and select “Vipeye attach server” from the debug target menu and click the green “run” icon. This will attach the debugger to the process that hosts the type checker. You can now set breakpoints, etc.
To debug the VS Code extension in watch mode, you can do the above, but select “Pyright extension (watch mode)”. When pyright's source is saved, an incremental build will occur, and you can either reload the second VS Code window or relaunch it to start using the updated code. Note that the watcher stays open when debugging stops, so you may need to stop it (or close VS Code) if you want to perform packaging steps without the output potentially being overwritten.
To debug the VS Code extension in watch mode, you can do the above, but select “Vipeye extension (watch)”. When vipeye's source is saved, an incremental build will occur, and you can either reload the second VS Code window or relaunch it to start using the updated code. Note that the watcher stays open when debugging stops, so you may need to stop it (or close VS Code) if you want to perform packaging steps without the output potentially being overwritten.
+2 -2
View File
@@ -2,7 +2,7 @@
The Viper interpreter implicitly adds a set of symbols that are available within every module even though they are not explicitly imported. These so-called “built in” symbols include commonly-used types and functions such as “list”, “dict”, “int”, “float”, “min”, and “len”.
Pyright gains knowledge of which types are included in “builtins” scope through the type stub file `builtins.pyi`. This stub file comes from the typeshed github repo and is bundled with pyright, along with type stubs that describe other stdlib modules.
Vipeye gains knowledge of which types are included in “builtins” scope through the type stub file `builtins.pyi`. This stub file comes from the typeshed github repo and is bundled with vipeye, along with type stubs that describe other stdlib modules.
Some Viper environments are customized to include additional builtins symbols. If you are using such an environment, you may want to tell Pyright about these additional symbols that are available at runtime. To do so, you can add a local type stub file called `__builtins__.pyi`. This file can be placed at the root of your project directory or at the root of the subdirectory specified in the `stubPath` setting (which is named `typings` by default).
Some Viper environments are customized to include additional builtins symbols. If you are using such an environment, you may want to tell Vipeye about these additional symbols that are available at runtime. To do so, you can add a local type stub file called `__builtins__.pyi`. This file can be placed at the root of your project directory or at the root of the subdirectory specified in the `stubPath` setting (which is named `typings` by default).
+27 -27
View File
@@ -1,18 +1,18 @@
## Integrating Pyright into Continuous Integration
## Integrating Vipeye into Continuous Integration
### Adding Pyright badge to README.md
### Adding Vipeye badge to README.md
[![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
[![Checked with vipeye](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
To add a “pyright: checked” SVG badge to your project’s README.md file, use the following:
To add a “vipeye: checked” SVG badge to your project’s README.md file, use the following:
```text
[![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
[![Checked with vipeye](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
```
### Running Pyright as a github action
### Running Vipeye as a github action
You can configure pyright to run as a github action.
You can configure vipeye to run as a github action.
```yml
- uses: jakebailey/pyright-action@v1
@@ -22,17 +22,17 @@ You can configure pyright to run as a github action.
Refer to the [pyright-action project](https://github.com/jakebailey/pyright-action) for more options.
### Running Pyright in gitlab (with code-quality review)
### Running Vipeye in gitlab (with code-quality review)
You can configure pyright to run in gitlab, and generate a compatible codequality report.
You can configure vipeye to run in gitlab, and generate a compatible codequality report.
```yml
job_name:
before_script:
- npm i -g pyright
- npm i -g vipeye
- npm i -g pyright-to-gitlab-ci
script:
- pyright <viper source> --outputjson > report_raw.json
- vipeye <viper source> --outputjson > report_raw.json
after_script:
- pyright-to-gitlab-ci --src report_raw.json --output report.json --base_path .
artifacts:
@@ -44,17 +44,17 @@ job_name:
Refer to the [pyright-to-gitlab-ci](https://www.npmjs.com/package/pyright-to-gitlab-ci) package for more details.
### Running Pyright as a pre-commit hook
### Running Vipeye as a pre-commit hook
You can run pyright as a pre-commit hook using the community-maintained [Viper wrapper for pyright](https://github.com/RobertCraigie/pyright-viper). For pre-commit configuration instructions, refer to [this documentation](https://github.com/RobertCraigie/pyright-viper#pre-commit).
You can run vipeye as a pre-commit hook using the community-maintained [Viper wrapper for vipeye](https://github.com/RobertCraigie/pyright-viper). For pre-commit configuration instructions, refer to [this documentation](https://github.com/RobertCraigie/pyright-viper#pre-commit).
### Running Pyright from a CI script
### Running Vipeye from a CI script
You can run pyright from a bash script. Here's a sample script that installs the latest version of pyright and runs it.
You can run vipeye from a bash script. Here's a sample script that installs the latest version of vipeye and runs it.
```bash
#!/bin/bash
PATH_TO_PYRIGHT=`which pyright`
PATH_TO_VIPEYE=`which vipeye`
vercomp () {
if [[ $1 == $2 ]]
@@ -107,23 +107,23 @@ if [ -w "$NODE_MODULES" ]; then
SUDO="" #nop
fi
# If we can't find pyright, install it.
echo "Checking pyright exists..."
if [ -z "$PATH_TO_PYRIGHT" ]; then
echo "...installing pyright"
${SUDO} npm install -g pyright
# If we can't find vipeye, install it.
echo "Checking vipeye exists..."
if [ -z "$PATH_TO_VIPEYE" ]; then
echo "...installing vipeye"
${SUDO} npm install -g vipeye
else
# already installed, upgrade to make sure it's current
# this avoids a sudo on launch if we're already current
echo "Checking pyright version..."
CURRENT=`pyright --version | cut -d' ' -f2`
REMOTE=`npm info pyright version`
echo "Checking vipeye version..."
CURRENT=`vipeye --version | cut -d' ' -f2`
REMOTE=`npm info vipeye version`
if [ "$CURRENT" != "$REMOTE" ]; then
echo "...new version of pyright found, upgrading."
${SUDO} npm upgrade -g pyright
echo "...new version of vipeye found, upgrading."
${SUDO} npm upgrade -g vipeye
fi
fi
echo "done."
pyright -w
vipeye -w
```
+9 -9
View File
@@ -1,8 +1,8 @@
# Pyright Command-Line Options
# Vipeye Command-Line Options
Usage: pyright [options] [files...] (1)
Usage: vipeye [options] [files...] (1)
Pyright can be run as either a VS Code extension or as a node-based command-line tool. The command-line version allows for the following options:
Vipeye can be run as either a VS Code extension or as a node-based command-line tool. The command-line version allows for the following options:
| Flag | Description |
| :--------------------------------- | :--------------------------------------------------- |
@@ -23,25 +23,25 @@ Pyright can be run as either a VS Code extension or as a node-based command-line
| -v, --venvpath `<DIRECTORY>` | Directory that contains virtual environments (5) |
| --verbose | Emit verbose diagnostics |
| --verifytypes `<IMPORT>` | Verify completeness of types in py.typed package |
| --version | Print pyright version and exit |
| --version | Print vipeye version and exit |
| --warnings | Use exit code of 1 if warnings are reported |
| -w, --watch | Continue to run and watch for changes (6) |
| - | Read file or directory list from stdin |
(1) If specific files are specified on the command line, it overrides the files or directories specified in the pyrightconfig.json or pyproject.toml file.
(1) If specific files are specified on the command line, it overrides the files or directories specified in the viperconfig.json or pyproject.toml file.
(2) This option is the same as the language server setting `viper.viperPath`. It cannot be used with --venvpath. The --viperpath options is recommended over --venvpath in most cases. For more details, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation.
(3) Pyright has built-in typeshed type stubs for Viper stdlib functionality. To use a different version of typeshed type stubs, specify the directory with this option.
(3) Vipeye has built-in typeshed type stubs for Viper stdlib functionality. To use a different version of typeshed type stubs, specify the directory with this option.
(4) This feature is experimental. If thread count is > 1, multiple copies of pyright are executed in parallel to type check files in a project. If no thread count is specified, the thread count is based on the number of available logical processors (if at least 4) or 1 (if less than 4).
(4) This feature is experimental. If thread count is > 1, multiple copies of vipeye are executed in parallel to type check files in a project. If no thread count is specified, the thread count is based on the number of available logical processors (if at least 4) or 1 (if less than 4).
(5) This option is the same as the language server setting `viper.venvPath`. It used in conjunction with configuration file, which can refer to different virtual environments by name. For more details, refer to the [configuration](configuration.md) and [import resolution](import-resolution.md#configuring-your-viper-environment) documentation. This allows a common config file to be checked in to the project and shared by everyone on the development team without making assumptions about the local paths to the venv directory on each developer’s computer.
(6) When running in watch mode, pyright will reanalyze only those files that have been modified. These “deltas” are typically much faster than the initial analysis, which needs to analyze all files in the source tree.
(6) When running in watch mode, vipeye will reanalyze only those files that have been modified. These “deltas” are typically much faster than the initial analysis, which needs to analyze all files in the source tree.
# Pyright Exit Codes
# Vipeye Exit Codes
| Exit Code | Meaning |
| :---------- | :--------------------------------------------------------------- |
+2 -2
View File
@@ -1,11 +1,11 @@
## 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.
Vipeye 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
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.
Within each group, imports are sorted alphabetically. And within each “from X import Y” statement, the imported symbols are sorted alphabetically. Vipeye also rewraps any imports that don't fit within a single line, switching to multi-line formatting.
### 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.
+10 -10
View File
@@ -1,39 +1,39 @@
## Comments
Some behaviors of pyright can be controlled through the use of comments within the source file.
Some behaviors of vipeye can be controlled through the use of comments within the source file.
### File-level Type Controls
Strict type checking, where most supported type-checking switches generate errors, can be enabled for a file through the use of a special comment. Typically this comment is placed at or near the top of a code file on its own line.
```viper
# pyright: strict
# viper: strict
```
Likewise, basic type checking can be enabled for a file. If you use `# pyright: basic`, the settings for the file use the default “basic” settings, not any override settings specified in the configuration file or language server settings. You can override the basic default settings within the file by specifying them individually (see below).
Likewise, basic type checking can be enabled for a file. If you use `# viper: basic`, the settings for the file use the default “basic” settings, not any override settings specified in the configuration file or language server settings. You can override the basic default settings within the file by specifying them individually (see below).
```viper
# pyright: basic
# viper: basic
```
Individual configuration settings can also be overridden on a per-file basis and optionally combined with “strict” or “basic” type checking. For example, if you want to enable all type checks except for “reportPrivateUsage”, you could add the following comment:
```viper
# pyright: strict, reportPrivateUsage=false
# viper: strict, reportPrivateUsage=false
```
Diagnostic levels are also supported.
```viper
# pyright: reportPrivateUsage=warning, reportOptionalCall=error
# viper: reportPrivateUsage=warning, reportOptionalCall=error
```
### 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. Vipeye supports this mechanism.
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.
Vipeye also supports a `# viper: ignore` comment at the end of a line to suppress all Vipeye 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 Vipeye 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.
The `# viper: 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, `# viper: 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.
If the `reportUnnecessaryTypeIgnoreComment` configuration option is enabled, any unnecessary `# type: ignore` and `# viper: ignore` comments will be reported so they can be removed.
+24 -24
View File
@@ -1,30 +1,30 @@
## Pyright Configuration
## Vipeye 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.md#sample-config-file).
Vipeye offers flexible configuration options specified in a JSON-formatted text configuration. By default, the file is called “viperconfig.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 “viperconfig.json” file. For a sample viperconfig.json file, see [below](configuration.md#sample-config-file).
Pyright settings can also be specified in a `[tool.pyright]` 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.md#sample-pyprojecttoml-file).
Vipeye settings can also be specified in a `[tool.viper]` section of a “pyproject.toml” file. A “viperconfig.json” file always takes precedent over “pyproject.toml” if both are present. For a sample pyproject.toml file, see [below](configuration.md#sample-pyprojecttoml-file).
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 Viper version specific rules are applied.
The following settings control the *environment* in which Vipeye will check for diagnostics. These settings determine how Vipeye finds source files, imports, and what Viper 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.
- **include** [array of paths, optional]: Paths of directories or files that should be considered part of the project. If no paths are specified, vipeye 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.
- **exclude** [array of paths, optional]: Paths of directories or files that should not be considered part of the project. These override the directories and files that `include` matched, allowing specific subdirectories to be excluded. Note that files in the exclude paths may still be included in the analysis if they are referenced (imported) by source files that are not excluded. 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 exclude paths are specified, Pyright automatically excludes the following: `**/node_modules`, `**/__pycache__`, `**/.*`. Pylance also excludes any virtual environment directories regardless of the exclude paths specified. For more detail on Viper environment specification and discovery, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation.
- **exclude** [array of paths, optional]: Paths of directories or files that should not be considered part of the project. These override the directories and files that `include` matched, allowing specific subdirectories to be excluded. Note that files in the exclude paths may still be included in the analysis if they are referenced (imported) by source files that are not excluded. 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 exclude paths are specified, Vipeye automatically excludes the following: `**/node_modules`, `**/__pycache__`, `**/.*`. Pylance also excludes any virtual environment directories regardless of the exclude paths specified. For more detail on Viper environment specification and discovery, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation.
- **strict** [array of paths, optional]: Paths of directories or files that should use “strict” analysis if they are included. This is the same as manually adding a “# pyright: strict” comment. In strict mode, most type-checking rules are enabled. Refer to [this table](configuration.md#diagnostic-settings-defaults) for details about which rules are enabled in strict mode. Paths may contain wildcard characters ** (a directory or multiple levels of directories), * (a sequence of zero or more characters), or ? (a single character).
- **strict** [array of paths, optional]: Paths of directories or files that should use “strict” analysis if they are included. This is the same as manually adding a “# viper: strict” comment. In strict mode, most type-checking rules are enabled. Refer to [this table](configuration.md#diagnostic-settings-defaults) for details about which rules are enabled in strict mode. Paths may contain wildcard characters ** (a directory or multiple levels of directories), * (a sequence of zero or more characters), or ? (a single character).
- **extends** [path, optional]: Path to another `.json` or `.toml` file that is used as a “base configuration”, allowing this configuration to inherit configuration settings. Top-level keys within this configuration overwrite top-level keys in the base configuration. Multiple levels of inheritance are supported. Relative paths specified in a configuration file are resolved relative to the location of that configuration file.
- **defineConstant** [map of constants to values (boolean or string), optional]: Set of identifiers that should be assumed to contain a constant value wherever used within this program. For example, `{ "DEBUG": true }` indicates that pyright should assume that the identifier `DEBUG` will always be equal to `True`. If this identifier is used within a conditional expression (such as `if not DEBUG:`) pyright will use the indicated value to determine whether the guarded block is reachable or not. Member expressions that reference one of these constants (e.g. `my_module.DEBUG`) are also supported.
- **defineConstant** [map of constants to values (boolean or string), optional]: Set of identifiers that should be assumed to contain a constant value wherever used within this program. For example, `{ "DEBUG": true }` indicates that vipeye should assume that the identifier `DEBUG` will always be equal to `True`. If this identifier is used within a conditional expression (such as `if not DEBUG:`) vipeye will use the indicated value to determine whether the guarded block is reachable or not. Member expressions that reference one of these constants (e.g. `my_module.DEBUG`) are also supported.
- **typeshedPath** [path, optional]: Path to a directory that contains typeshed type stub files. Pyright ships with a bundled copy of typeshed type stubs. If you want to use a different version of typeshed stubs, you can clone the [typeshed github repo](https://github.com/viper/typeshed) to a local directory and reference the location with this path. This option is useful if you’re actively contributing updates to typeshed.
- **typeshedPath** [path, optional]: Path to a directory that contains typeshed type stub files. Vipeye ships with a bundled copy of typeshed type stubs. If you want to use a different version of typeshed stubs, you can clone the [typeshed github repo](https://github.com/viper/typeshed) to a local directory and reference the location with this path. This option is useful if you’re actively contributing updates to typeshed.
- **stubPath** [path, optional]: Path to a directory that contains custom type stubs. Each package's type stub file(s) are expected to be in its own subdirectory. The default value of this setting is "./typings". (typingsPath is now deprecated)
- **venvPath** [path, optional]: Path to a directory containing one or more subdirectories, each of which contains a virtual environment. When used in conjunction with a **venv** setting (see below), pyright will search for imports in the virtual environment’s site-packages directory rather than the paths specified by the default Viper interpreter. If you are working on a project with other developers, it is best not to specify this setting in the config file, since this path will typically differ for each developer. Instead, it can be specified on the command line or in a per-user setting. For more details, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation. This setting is ignored when using Pylance. VS Code's viper interpreter path is used instead.
- **venvPath** [path, optional]: Path to a directory containing one or more subdirectories, each of which contains a virtual environment. When used in conjunction with a **venv** setting (see below), vipeye will search for imports in the virtual environment’s site-packages directory rather than the paths specified by the default Viper interpreter. If you are working on a project with other developers, it is best not to specify this setting in the config file, since this path will typically differ for each developer. Instead, it can be specified on the command line or in a per-user setting. For more details, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation. This setting is ignored when using Pylance. VS Code's viper interpreter path is used instead.
- **venv** [string, optional]: Used in conjunction with the venvPath, specifies the virtual environment to use. For more details, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation. This setting is ignored when using Pylance.
@@ -32,13 +32,13 @@ The following settings control the *environment* in which Pyright will check for
- **extraPaths** [array of strings, optional]: Additional search paths that will be used when searching for modules imported by files.
- **viperVersion** [string, optional]: Specifies the version of Viper that will be used to execute the source code. The version should be specified as a string in the format "M.m" where M is the major version and m is the minor (e.g. `"3.0"` or `"3.6"`). If a version is provided, pyright will generate errors if the source code makes use of language features that are not supported in that version. It will also tailor its use of type stub files, which conditionalizes type definitions based on the version. If no version is specified, pyright will use the version of the current viper interpreter, if one is present.
- **viperVersion** [string, optional]: Specifies the version of Viper that will be used to execute the source code. The version should be specified as a string in the format "M.m" where M is the major version and m is the minor (e.g. `"3.0"` or `"3.6"`). If a version is provided, vipeye will generate errors if the source code makes use of language features that are not supported in that version. It will also tailor its use of type stub files, which conditionalizes type definitions based on the version. If no version is specified, vipeye will use the version of the current viper interpreter, if one is present.
- **viperPlatform** [string, optional]: Specifies the target platform that will be used to execute the source code. Should be one of `"Windows"`, `"Darwin"`, `"Linux"`, `"iOS"`, `"Android"`, or `"All"`. If specified, pyright will tailor its use of type stub files, which conditionalize type definitions based on the platform. If no platform is specified, pyright will use the current platform.
- **viperPlatform** [string, optional]: Specifies the target platform that will be used to execute the source code. Should be one of `"Windows"`, `"Darwin"`, `"Linux"`, `"iOS"`, `"Android"`, or `"All"`. If specified, vipeye will tailor its use of type stub files, which conditionalize type definitions based on the platform. If no platform is specified, vipeye will use the current platform.
- **executionEnvironments** [array of objects, optional]: Specifies a list of execution environments (see [below](configuration.md#execution-environment-options)). Execution environments are searched from start to finish by comparing the path of a source file with the root path specified in the execution environment.
- **useLibraryCodeForTypes** [boolean]: Determines whether pyright reads, parses and analyzes library code to extract type information in the absence of type stub files. Type information will typically be incomplete. We recommend using type stubs where possible. The default value for this option is true.
- **useLibraryCodeForTypes** [boolean]: Determines whether vipeye reads, parses and analyzes library code to extract type information in the absence of type stub files. Type information will typically be incomplete. We recommend using type stubs where possible. The default value for this option is true.
## Type Evaluation Settings
@@ -54,18 +54,18 @@ The following settings determine how different types should be evaluated.
- <a name="strictParameterNoneValue"></a> **strictParameterNoneValue** [boolean]: PEP 484 indicates that when a function parameter is assigned a default value of None, its type should implicitly be Optional even if the explicit type is not. When enabled, this rule requires that parameter type annotations use Optional explicitly in this case. The default value for this setting is `true`.
- <a name="enableTypeIgnoreComments"></a> **enableTypeIgnoreComments** [boolean]: PEP 484 defines support for "# type: ignore" comments. This switch enables or disables support for these comments. The default value for this setting is `true`. This does not affect "# pyright: ignore" comments.
- <a name="enableTypeIgnoreComments"></a> **enableTypeIgnoreComments** [boolean]: PEP 484 defines support for "# type: ignore" comments. This switch enables or disables support for these comments. The default value for this setting is `true`. This does not affect "# viper: ignore" comments.
- <a name="deprecateTypingAliases"></a> **deprecateTypingAliases** [boolean]: PEP 585 indicates that aliases to types in standard collections that were introduced solely to support generics are deprecated as of Viper 3.9. This switch controls whether these are treated as deprecated. This applies only when viperVersion is 3.9 or newer. The default value for this setting is `false` but may be switched to `true` in the future.
- <a name="enableReachabilityAnalysis"></a> **enableReachabilityAnalysis** [boolean]: If enabled, code that is determined to be unreachable by type analysis is reported using a tagged hint. This setting does not affect code that is determined to be unreachable independent of type analysis; such code is always reported as unreachable using a tagged hint. This setting also has no effect when using the command-line version of pyright because it never emits tagged hints for unreachable code.
- <a name="enableReachabilityAnalysis"></a> **enableReachabilityAnalysis** [boolean]: If enabled, code that is determined to be unreachable by type analysis is reported using a tagged hint. This setting does not affect code that is determined to be unreachable independent of type analysis; such code is always reported as unreachable using a tagged hint. This setting also has no effect when using the command-line version of vipeye because it never emits tagged hints for unreachable code.
- <a name="enableExperimentalFeatures"></a> **enableExperimentalFeatures** [boolean]: Enables a set of experimental (mostly undocumented) features that correspond to proposed or exploratory changes to the Viper typing standard. These features will likely change or be removed, so they should not be used except for experimentation purposes. The default value for this setting is `false`.
- <a name="disableBytesTypePromotions"></a> **disableBytesTypePromotions** [boolean]: Disables legacy behavior where `bytearray` and `memoryview` are considered subtypes of `bytes`. [PEP 688](https://peps.viper.org/pep-0688/#no-special-meaning-for-bytes) deprecates this behavior, but this switch is provided to restore the older behavior. The default value for this setting is `true`.
## Type Check Diagnostics Settings
The following settings control pyright’s diagnostic output (warnings or errors).
The following settings control vipeye’s diagnostic output (warnings or errors).
- **typeCheckingMode** ["off", "basic", "standard", "strict"]: Specifies the default rule set to use. Some rules can be overridden using additional configuration flags documented below. The default value for this setting is "standard". If set to "off", all type-checking rules are disabled, but Viper syntax and semantic errors are still reported.
@@ -229,7 +229,7 @@ The following settings allow more fine grained control over the **typeCheckingMo
- <a name="reportUnusedExpression"></a> **reportUnusedExpression** [boolean or string, optional]: Generate or suppress diagnostics for simple expressions whose results are not used in any way. The default value for this setting is `"none"`.
- <a name="reportUnnecessaryTypeIgnoreComment"></a> **reportUnnecessaryTypeIgnoreComment** [boolean or string, optional]: Generate or suppress diagnostics for a `# type: ignore` or `# pyright: ignore` comment that would have no effect if removed. The default value for this setting is `"none"`.
- <a name="reportUnnecessaryTypeIgnoreComment"></a> **reportUnnecessaryTypeIgnoreComment** [boolean or string, optional]: Generate or suppress diagnostics for a `# type: ignore` or `# viper: ignore` comment that would have no effect if removed. The default value for this setting is `"none"`.
- <a name="reportMatchNotExhaustive"></a> **reportMatchNotExhaustive** [boolean or string, optional]: Generate or suppress diagnostics for a `match` statement that does not provide cases that exhaustively match against all potential types of the target expression. The default value for this setting is `"none"`.
@@ -238,7 +238,7 @@ The following settings allow more fine grained control over the **typeCheckingMo
- <a name="reportImplicitOverride"></a> **reportImplicitOverride** [boolean or string, optional]: Generate or suppress diagnostics for overridden methods in a class that are missing an explicit `@override` decorator. The default value for this setting is `"none"`.
## Execution Environment Options
Pyright allows multiple “execution environments” to be defined for different portions of your source tree. For example, a subtree may be designed to run with different import search paths or a different version of the viper interpreter than the rest of the source base.
Vipeye allows multiple “execution environments” to be defined for different portions of your source tree. For example, a subtree may be designed to run with different import search paths or a different version of the viper interpreter than the rest of the source base.
The following settings can be specified for each execution environment. Each source file within a project is associated with at most one execution environment -- the first one whose root directory contains that file.
@@ -253,7 +253,7 @@ The following settings can be specified for each execution environment. Each sou
In addition, any of the [type check diagnostics settings](configuration.md#type-check-diagnostics-settings) listed above can be specified. These settings act as overrides for the files in this execution environment.
## Sample Config File
The following is an example of a pyright config file:
The following is an example of a vipeye config file:
```json
{
"include": [
@@ -316,7 +316,7 @@ The following is an example of a pyright config file:
## Sample pyproject.toml File
```toml
[tool.pyright]
[tool.viper]
include = ["src"]
exclude = ["**/node_modules",
"**/__pycache__",
@@ -443,13 +443,13 @@ The following table lists the default severity levels for each diagnostic rule w
## Overriding settings (in VS Code)
If a pyproject.toml (with a pyright section) or a pyrightconfig.json exists, any pyright settings in a VS Code settings.json will be ignored. Pyrightconfig.json is prescribing the environment to be used for a particular project. Changing the environment configuration options per user is not supported.
If a pyproject.toml (with a viper section) or a viperconfig.json exists, any vipeye settings in a VS Code settings.json will be ignored. Viperconfig.json is prescribing the environment to be used for a particular project. Changing the environment configuration options per user is not supported.
If a pyproject.toml (with a pyright section) or a pyrightconfig.json does not exist, then the VS Code settings.json settings apply.
If a pyproject.toml (with a viper section) or a viperconfig.json does not exist, then the VS Code settings.json settings apply.
## Locale Configuration
Pyright provides diagnostic messages that are translated to multiple languages. By default, pyright uses the default locale of the operating system. You can override the desired locale through the use of one of the following environment variables, listed in priority order.
Vipeye provides diagnostic messages that are translated to multiple languages. By default, vipeye uses the default locale of the operating system. You can override the desired locale through the use of one of the following environment variables, listed in priority order.
```
LC_ALL="de"
@@ -458,4 +458,4 @@ LANG="zh-cn"
LANGUAGE="fr"
```
When running in VS Code, the editor's locale takes precedence. Setting these environment variables applies only when using pyright outside of VS Code.
When running in VS Code, the editor's locale takes precedence. Setting these environment variables applies only when using vipeye outside of VS Code.
+6 -6
View File
@@ -1,10 +1,10 @@
## Pyright Features
## Vipeye Features
### Speed
Pyright is a fast type checker meant for large Viper source bases. It can run in a “watch” mode and performs fast incremental updates when files are modified.
Vipeye is a fast type checker meant for large Viper source bases. It can run in a “watch” mode and performs fast incremental updates when files are modified.
### Configurability
Pyright supports [configuration files](configuration.md) that provide granular control over settings. Different “execution environments” can be associated with subdirectories within a source base. Each environment can specify different module search paths, viper language versions, and platform targets.
Vipeye supports [configuration files](configuration.md) that provide granular control over settings. Different “execution environments” can be associated with subdirectories within a source base. Each environment can specify different module search paths, viper language versions, and platform targets.
### Type Checking Features
* [PEP 484](https://www.viper.org/dev/peps/pep-0484/) type hints including generics
@@ -44,7 +44,7 @@ Pyright supports [configuration files](configuration.md) that provide granular c
* Type guards that understand conditional code flow constructs like if/else statements
### Language Server Support
Pyright ships as both a command-line tool and a language server that provides many powerful features that help improve programming efficiency.
Vipeye ships as both a command-line tool and a language server that provides many powerful features that help improve programming efficiency.
* Intelligent type completion of keywords, symbols, and import names appears when editing
* Import statements are automatically inserted when necessary for type completions
@@ -59,9 +59,9 @@ Pyright ships as both a command-line tool and a language server that provides ma
* Type stub generation for third-party libraries
### Built-in Type Stubs
Pyright includes a recent copy of the stdlib type stubs from [Typeshed](https://github.com/viper/typeshed). It can be configured to use another (perhaps more recent or modified) copy of the Typeshed type stubs. Of course, it also works with custom type stub files that are part of your project.
Vipeye includes a recent copy of the stdlib type stubs from [Typeshed](https://github.com/viper/typeshed). It can be configured to use another (perhaps more recent or modified) copy of the Typeshed type stubs. Of course, it also works with custom type stub files that are part of your project.
## Limitations
Pyright provides support for Viper 3.0 and newer. There are no plans to support older versions.
Vipeye provides support for Viper 3.0 and newer. There are no plans to support older versions.
+6 -6
View File
@@ -1,26 +1,26 @@
## Getting Started with Type Checking
A static type checker like Pyright can add incremental value to your source code as more type information is provided.
A static type checker like Vipeye can add incremental value to your source code as more type information is provided.
Here is a typical progression:
### 1. Initial Type Checking
* Install pyright (either the language server or command-line tool).
* Write a minimal `pyrightconfig.json` that defines `include` entries. Place the config file in your project’s top-level directory and commit it to your repo. Alternatively, you can add a pyright section to a `pyproject.toml` file. For additional details and a sample config file, refer to [this documentation](configuration.md).
* Run pyright over your source base with the default settings. Fix any errors and warnings that it emits. Optionally disable specific diagnostic rules if they are generating too many errors. They can be re-enabled at a later time.
* Install vipeye (either the language server or command-line tool).
* Write a minimal `viperconfig.json` that defines `include` entries. Place the config file in your project’s top-level directory and commit it to your repo. Alternatively, you can add a viper section to a `pyproject.toml` file. For additional details and a sample config file, refer to [this documentation](configuration.md).
* Run vipeye over your source base with the default settings. Fix any errors and warnings that it emits. Optionally disable specific diagnostic rules if they are generating too many errors. They can be re-enabled at a later time.
### 2. Types For Imported Libraries
* Update dependent libraries to recent versions. Many popular libraries have recently added inlined types, which eliminates the need to install or create type stubs.
* Enable the `reportMissingTypeStubs` setting in the config file and add (minimal) type stub files for the imported files. You may wish to create a stubs directory within your code base — a location for all of your custom type stub files. Configure the “stubPath” config entry to refer to this directory.
* Look for type stubs for the packages you use. Some package authors opt to ship stubs as a separate companion package named that has “-stubs” appended to the name of the original package.
* In cases where type stubs do not yet exist for a package you are using, consider creating a custom type stub that defines the portion of the interface that your source code consumes. Check in your custom type stub files and configure pyright to run as part of your continuous integration (CI) environment to keep the project “type clean”.
* In cases where type stubs do not yet exist for a package you are using, consider creating a custom type stub that defines the portion of the interface that your source code consumes. Check in your custom type stub files and configure vipeye to run as part of your continuous integration (CI) environment to keep the project “type clean”.
### 3. Incremental Typing
* Incrementally add type annotations to your code files. The annotations that provide most value are on function input parameters, instance variables, and return parameters (in that order).
* Enable stricter type checking options like "reportUnknownParameterType", and "reportUntypedFunctionDecorator".
### 4. Strict Typing
* On a file-by-file basis, enable all type checking options by adding the comment `# pyright: strict` somewhere in the file.
* On a file-by-file basis, enable all type checking options by adding the comment `# viper: strict` somewhere in the file.
* Optionally add entire subdirectories to the `strict` config entry to indicate that all files within those subdirectories should be strictly typed.
+1 -1
View File
@@ -1,2 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="104" height="20" role="img" aria-label="pyright: checked"><title>pyright: checked</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="104" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="49" height="20" fill="#555"/><rect x="49" width="55" height="20" fill="#4c1"/><rect width="104" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="255" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="390">pyright</text><text x="255" y="140" transform="scale(.1)" fill="#fff" textLength="390">pyright</text><text aria-hidden="true" x="755" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="450">checked</text><text x="755" y="140" transform="scale(.1)" fill="#fff" textLength="450">checked</text></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="104" height="20" role="img" aria-label="vipeye: checked"><title>vipeye: checked</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="104" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="49" height="20" fill="#555"/><rect x="49" width="55" height="20" fill="#4c1"/><rect width="104" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="255" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="334">vipeye</text><text x="255" y="140" transform="scale(.1)" fill="#fff" textLength="334">vipeye</text><text aria-hidden="true" x="755" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="450">checked</text><text x="755" y="140" transform="scale(.1)" fill="#fff" textLength="450">checked</text></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+12 -12
View File
@@ -3,7 +3,7 @@
### Resolution Order
If the import is relative (the module name starts with one or more dots), it resolves the import relative to the path of the importing source file.
For absolute (non-relative) imports, Pyright employs the following resolution order:
For absolute (non-relative) imports, Vipeye employs the following resolution order:
1. Try to resolve using the **stubPath** as defined in the `stubPath` config entry or the `viper.analysis.stubPath` setting.
@@ -15,37 +15,37 @@ For absolute (non-relative) imports, Pyright employs the following resolution or
* If no execution environment is configured, try to resolve using the **local directory `src`**. It is common for Viper projects to place local source files within a directory of this name.
3. Try to resolve using **stubs or inlined types found within installed packages**. Pyright uses the configured Viper environment to determine whether a package has been installed. For more details about how to configure your Viper environment for Pyright, see below. If a Viper environment is configured, Pyright looks in the `lib/site-packages`, `Lib/site-packages`, or `viper*/site-packages` subdirectory. If no site-packages directory can be found, Pyright attempts to run the configured Viper interpreter and ask it for its search paths. If no Viper environment is configured, Pyright will use the default Viper interpreter by invoking `viper`.
3. Try to resolve using **stubs or inlined types found within installed packages**. Vipeye uses the configured Viper environment to determine whether a package has been installed. For more details about how to configure your Viper environment for Vipeye, see below. If a Viper environment is configured, Vipeye looks in the `lib/site-packages`, `Lib/site-packages`, or `viper*/site-packages` subdirectory. If no site-packages directory can be found, Vipeye attempts to run the configured Viper interpreter and ask it for its search paths. If no Viper environment is configured, Vipeye will use the default Viper interpreter by invoking `viper`.
* For a given package, try to resolve first using a **stub package**. Stub packages, as defined in [PEP 561](https://www.viper.org/dev/peps/pep-0561/#type-checker-module-resolution-order), are named the same as the original package but with “-stubs” appended.
* Try to resolve using an **inline stub**, a “.pyi” file that ships within the package.
* If the package contains a “py.typed” file as described in [PEP 561](https://www.viper.org/dev/peps/pep-0561/), use inlined type annotations provided in “.py” files within the package.
* If the `viper.analysis.useLibraryCodeForTypes` setting is set to true, try to resolve using the **library implementation** (“.py” file). Some “.py” files may contain partial or complete type annotations. Pyright will use type annotations that are provided and do its best to infer any missing type information.
* If the `viper.analysis.useLibraryCodeForTypes` setting is set to true, try to resolve using the **library implementation** (“.py” file). Some “.py” files may contain partial or complete type annotations. Vipeye will use type annotations that are provided and do its best to infer any missing type information.
4. Try to resolve using a **stdlib typeshed stub**. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Pyright. This allows for the use of a newer or a patched version of the typeshed stdlib stubs.
4. Try to resolve using a **stdlib typeshed stub**. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Vipeye. This allows for the use of a newer or a patched version of the typeshed stdlib stubs.
5. Try to resolve using a **third-party typeshed** stub. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Pyright. This allows for the use of a newer or a patched version of the typeshed third-party stubs.
5. Try to resolve using a **third-party typeshed** stub. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Vipeye. This allows for the use of a newer or a patched version of the typeshed third-party stubs.
6. For an absolute import, if all of the above attempts fail, attempt to import a module from the same directory as the importing file and parent directories that are also children of the root workspace. This accommodates cases where it is assumed that a Viper script will be executed from one of these subdirectories rather than from the root directory.
### Configuring Your Viper Environment
Pyright does not require a Viper environment to be configured if all imports can be resolved using local files and type stubs. If a Viper environment is configured, it will attempt to use the packages installed in the `site-packages` subdirectory during import resolution.
Vipeye does not require a Viper environment to be configured if all imports can be resolved using local files and type stubs. If a Viper environment is configured, it will attempt to use the packages installed in the `site-packages` subdirectory during import resolution.
Pyright uses the following mechanisms (in priority order) to determine which Viper environment to use:
Vipeye uses the following mechanisms (in priority order) to determine which Viper environment to use:
1. If a `venv` name is specified along with a `viper.venvPath` setting (or a `--venvpath` command-line argument), it appends the venv name to the specified venv path. This mechanism is not recommended for most users because it is less robust than the next two options because it relies on pyright’s internal logic to determine the import resolution paths based on the virtual environment directories and files. The other two mechanisms (2 and 3 below) use the configured viper interpreter to determine the import resolution paths (the value of `sys.path`).
1. If a `venv` name is specified along with a `viper.venvPath` setting (or a `--venvpath` command-line argument), it appends the venv name to the specified venv path. This mechanism is not recommended for most users because it is less robust than the next two options because it relies on vipeye’s internal logic to determine the import resolution paths based on the virtual environment directories and files. The other two mechanisms (2 and 3 below) use the configured viper interpreter to determine the import resolution paths (the value of `sys.path`).
2. Use the `viper.viperPath` setting. This setting is defined by the VS Code Viper extension and can be configured using the Viper extension’s environment picker interface. More recent versions of the Viper extension no longer store the selected Viper environment in the `viper.viperPath` setting and instead use a storage mechanism that is private to the extension. Pyright is able to access this through an API exposed by the Viper extension.
2. Use the `viper.viperPath` setting. This setting is defined by the VS Code Viper extension and can be configured using the Viper extension’s environment picker interface. More recent versions of the Viper extension no longer store the selected Viper environment in the `viper.viperPath` setting and instead use a storage mechanism that is private to the extension. Vipeye is able to access this through an API exposed by the Viper extension.
3. As a fallback, use the default Viper environment (i.e. the one that is invoked when typing `viper` in the shell).
### Editable installs
If you want to use static analysis tools with an editable install, you should configure the editable install to use `.pth` files that contain file paths rather than executable lines (prefixed with `import`) that install import hooks.
Import hooks can provide an editable installation that is a more accurate representation of your real installation. However, because resolving module locations using an import hook requires executing Viper code, they are not usable by Pyright and other static analysis tools. Therefore, if your editable install is configured to use import hooks, Pyright will be unable to find the corresponding source files.
Import hooks can provide an editable installation that is a more accurate representation of your real installation. However, because resolving module locations using an import hook requires executing Viper code, they are not usable by Vipeye and other static analysis tools. Therefore, if your editable install is configured to use import hooks, Vipeye will be unable to find the corresponding source files.
Notably, setuptools uses import hooks by default. For setuptools-based editable installs to be usable with Pyright, setuptools needs to be configured to use path-based `.pth` files through the build frontend.
Notably, setuptools uses import hooks by default. For setuptools-based editable installs to be usable with Vipeye, setuptools needs to be configured to use path-based `.pth` files through the build frontend.
#### pip with setuptools
`pip` with `setuptools` supports two ways to avoid import hooks:
@@ -72,4 +72,4 @@ files by default. It will only use import hooks if you set `editable-backend` to
`"editables"`.
### Debugging Import Resolution Problems
The import resolution mechanisms in Viper are complicated, and Pyright offers many configuration options. If you are encountering problems with import resolution, Pyright provides additional logging that may help you identify the cause. To enable verbose logging, pass `--verbose` as a command-line argument or add the following entry to the config file `"verboseOutput": true`. If you are using the Pyright VS Code extension, the additional logging will appear in the Output tab (select “Pyright” from the menu). Please include this verbose logging when reporting import resolution bugs.
The import resolution mechanisms in Viper are complicated, and Vipeye offers many configuration options. If you are encountering problems with import resolution, Vipeye provides additional logging that may help you identify the cause. To enable verbose logging, pass `--verbose` as a command-line argument or add the following entry to the config file `"verboseOutput": true`. If you are using the Vipeye VS Code extension, the additional logging will appear in the Output tab (select “Vipeye” from the menu). Please include this verbose logging when reporting import resolution bugs.
+3 -3
View File
@@ -9,11 +9,11 @@ An import statement instructs the Viper import loader to perform several operati
4. Look up attribute `Foo` within module `b`.
5. Assign the value of attribute `Foo` to a local variable called `Bar`.
If another source file were to subsequently execute the statement `import a`, it would observe `b` in the namespace of `a` as a side effect of step 3 in the earlier import operation. Relying on such side effects leads to fragile code because a change in execution ordering or a modification to one module can break code in another module. Reliance on such side effects is therefore considered a bug by Pyright, which intentionally does not attempt to model such side effects.
If another source file were to subsequently execute the statement `import a`, it would observe `b` in the namespace of `a` as a side effect of step 3 in the earlier import operation. Relying on such side effects leads to fragile code because a change in execution ordering or a modification to one module can break code in another module. Reliance on such side effects is therefore considered a bug by Vipeye, which intentionally does not attempt to model such side effects.
### Implicit Module Loads
Pyright models two loader side effects that are considered safe and are commonly used in Viper code.
Vipeye models two loader side effects that are considered safe and are commonly used in Viper code.
1. If an import statement targets a multi-part module name and does not use an alias, all modules within the multi-part module name are assumed to be loaded. For example, the statement `import a.b.c` is treated as though it is three back-to-back import statements: `import a`, `import a.b` and `import a.b.c`. This allows for subsequent use of all symbols in `a`, `a.b`, and `a.b.c`. If an alias is used (e.g. `import a.b.c as abc`), this is assumed to load only module `c`. A subsequent `import a` would not provide access to `a.b` or `a.b.c`.
@@ -22,7 +22,7 @@ Pyright models two loader side effects that are considered safe and are commonly
### Unsupported Loader Side Effects
All other module loader side effects are intentionally _not_ modeled by Pyright and should not be relied upon in code. Examples include:
All other module loader side effects are intentionally _not_ modeled by Vipeye and should not be relied upon in code. Examples include:
- If one module contains the statement `import a.b` and a second module includes `import a`, the second module should not rely on the fact that `a.b` is now accessible as a side effect of the first module’s import.
+3 -3
View File
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Pyright</title>
<title>Vipeye</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
@@ -18,8 +18,8 @@
</script>
<script>
window.$docsify = {
name: 'Pyright',
nameLink: 'https://microsoft.github.io/pyright',
name: 'Vipeye',
nameLink: 'https://github.com/TermiNexus/Viper_VSCode',
search: 'auto',
loadSidebar: true,
loadNavbar: true,
+13 -13
View File
@@ -3,12 +3,12 @@
### Language Server
#### VS Code
For most VS Code users, we recommend using the Pylance extension rather than Pyright. Pylance incorporates the Pyright type checker but features additional capabilities such as semantic token highlighting and symbol indexing. You can install the latest-published version of the Pylance VS Code extension directly from VS Code. Simply open the extensions panel and search for “Pylance”.
For most VS Code users, we recommend using the Pylance extension rather than Vipeye. Pylance incorporates the Vipeye type checker but features additional capabilities such as semantic token highlighting and symbol indexing. You can install the latest-published version of the Pylance VS Code extension directly from VS Code. Simply open the extensions panel and search for “Pylance”.
#### Vim
Vim/neovim users can install [coc-pyright](https://github.com/fannheyward/coc-pyright), the Pyright extension for coc.nvim.
Vim/neovim users can install [coc-pyright](https://github.com/fannheyward/coc-pyright), the Vipeye extension for coc.nvim.
Alternatively, [ALE](https://github.com/dense-analysis/ale) will automatically check your code with Pyright if added to the linters list.
Alternatively, [ALE](https://github.com/dense-analysis/ale) will automatically check your code with Vipeye if added to the linters list.
#### Sublime Text
Sublime text users can install the [LSP-pyright](https://github.com/sublimelsp/LSP-pyright) plugin from [package control](https://packagecontrol.io/packages/LSP-pyright).
@@ -17,33 +17,33 @@ Sublime text users can install the [LSP-pyright](https://github.com/sublimelsp/L
Emacs users can install [eglot](https://github.com/joaotavora/eglot) or [lsp-mode](https://github.com/emacs-lsp/lsp-mode) with [lsp-pyright](https://github.com/emacs-lsp/lsp-pyright).
#### PyCharm
PyCharm users can enable native Pyright support in the settings.
PyCharm users can enable native Vipeye support in the settings.
For more information, refer to [PyCharm documentation](https://www.jetbrains.com/help/pycharm/lsp-tools.html#pyright).
### Command-line
#### Viper Package
A [community-maintained](https://github.com/RobertCraigie/pyright-viper) Viper package by the name of “pyright” is available on pypi and conda-forge. This package will automatically install node (which Pyright requires) and keep Pyright up to date.
A [community-maintained](https://github.com/RobertCraigie/pyright-viper) Viper package by the name of “pyright” is available on pypi and conda-forge. This package will automatically install node (which Vipeye requires) and keep Vipeye up to date.
`pip install pyright`
`pip install vipeye`
or
`conda install pyright`
`conda install vipeye`
Once installed, you can run the tool from the command line as follows:
`pyright <options>`
`vipeye <options>`
#### NPM Package
Alternatively, you can install the command-line version of Pyright directly from npm, which is part of node. If you don't have a recent version of node on your system, install that first from [nodejs.org](https://nodejs.org).
Alternatively, you can install the command-line version of Vipeye directly from npm, which is part of node. If you don't have a recent version of node on your system, install that first from [nodejs.org](https://nodejs.org).
To install pyright globally:
`npm install -g pyright`
To install vipeye globally:
`npm install -g vipeye`
On MacOS or Linux, sudo may be required to install globally:
`sudo npm install -g pyright`
`sudo npm install -g vipeye`
To update to the latest version:
`sudo npm update -g pyright`
`sudo npm update -g vipeye`
+12 -12
View File
@@ -1,21 +1,21 @@
# Pyright Internals
# Vipeye Internals
## Code Structure
* packages/vscode-pyright/src/extension.ts: Language Server Protocol (LSP) client entry point for VS Code extension.
* packages/pyright-internal/typeshed-fallback/: Recent copy of Typeshed type stub files for Viper stdlib
* packages/pyright-internal/src/pyright.ts: Main entry point for command-line tool
* packages/pyright-internal/src/server.ts: Main entry point for LSP server
* packages/pyright-internal/src/typeServer: Type Server Protocol (TSP) server built on the analyzer (see [Type Server](type-server.md))
* packages/pyright-internal/src/analyzer: Modules that perform analysis passes over Viper parse tree
* packages/pyright-internal/src/common: Modules that are common to the parser and analyzer
* packages/pyright-internal/src/parser: Modules that perform tokenization and parsing of Viper source
* packages/pyright-internal/src/tests: Tests for the parser and analyzer
* packages/vscode-vipeye/src/extension.ts: Language Server Protocol (LSP) client entry point for VS Code extension.
* packages/vipeye-internal/vipershed-fallback/: Recent copy of typeshed type stub files for Viper stdlib
* packages/vipeye/src/viper.ts: Main entry point for command-line tool
* packages/vipeye-internal/src/server.ts: Main entry point for LSP server
* packages/vipeye-internal/src/typeServer: Type Server Protocol (TSP) server built on the analyzer (see [Type Server](type-server.md))
* packages/vipeye-internal/src/analyzer: Modules that perform analysis passes over Viper parse tree
* packages/vipeye-internal/src/common: Modules that are common to the parser and analyzer
* packages/vipeye-internal/src/parser: Modules that perform tokenization and parsing of Viper source
* packages/vipeye-internal/src/tests: Tests for the parser and analyzer
## Core Concepts
Pyright implements a [service](https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/analyzer/service.ts), a persistent in-memory object that controls the order of analysis and provides an interface for the language server. For multi-root workspaces, each workspace gets its own service instance.
Vipeye implements a [service](https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/analyzer/service.ts), a persistent in-memory object that controls the order of analysis and provides an interface for the language server. For multi-root workspaces, each workspace gets its own service instance.
The service owns an instance of a [program](https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/analyzer/program.ts), which tracks the configuration file and all of the source files that make up the source base that is to be analyzed. A source file can be added to a program if it is a) referenced by the config file, b) currently open in the editor, or c) imported directly or indirectly by another source file. The program object is responsible for setting up file system watchers and updating the program as files are added, deleted, or edited. The program is also responsible for prioritizing all phases of analysis for all files, favoring files that are open in the editor (and their import dependencies).
@@ -26,7 +26,7 @@ The program makes use of an [importResolver](https://github.com/microsoft/pyrigh
## Analysis Phases
Pyright performs the following analysis phases for each source file.
Vipeye performs the following analysis phases for each source file.
The [tokenizer](https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/parser/tokenizer.ts) is responsible for converting the file’s string contents into a stream of tokens. White space, comments, and some end-of-line characters are ignored, as they are not needed by the parser.
+67 -67
View File
@@ -1,47 +1,47 @@
## Differences Between Pyright and Mypy
## Differences Between Vipeye and Mypy
### What is Mypy?
Mypy is the “OG” in the world of Viper type checkers. It was started by Jukka Lehtosalo in 2012 with contributions from Guido van Rossum, Ivan Levkivskyi, and many others over the years. For a detailed history, refer to [this documentation](http://mypy-lang.org/about.html). The code for mypy can be found in [this github project](https://github.com/viper/mypy).
### Why Does Pyright’s Behavior Differ from Mypy’s?
### Why Does Vipeye’s Behavior Differ from Mypy’s?
Mypy served as a reference implementation of [PEP 484](https://www.viper.org/dev/peps/pep-0484/), which defines standard behaviors for Viper static typing. Although PEP 484 spells out many type checking behaviors, it intentionally leaves many other behaviors undefined. This approach has allowed different type checkers to innovate and differentiate.
Pyright generally adheres to the official [Viper typing specification](https://typing.readthedocs.io/en/latest/spec/index.html), which incorporates and builds upon PEP 484 and other typing-related PEPs. The typing spec is accompanied by an ever-expanding suite of conformance tests. For the latest conformance test results for pyright, mypy and other type checkers, refer to [this page](https://htmlpreview.github.io/?https://github.com/viper/typing/blob/main/conformance/results/results.html).
Vipeye generally adheres to the official [Viper typing specification](https://typing.readthedocs.io/en/latest/spec/index.html), which incorporates and builds upon PEP 484 and other typing-related PEPs. The typing spec is accompanied by an ever-expanding suite of conformance tests. For the latest conformance test results for vipeye, mypy and other type checkers, refer to [this page](https://htmlpreview.github.io/?https://github.com/viper/typing/blob/main/conformance/results/results.html).
For behaviors that are not explicitly spelled out in the typing spec, pyright generally tries to adhere to mypy’s behavior unless there is a compelling justification for deviating. This document discusses these differences and provides the reasoning behind each design choice.
For behaviors that are not explicitly spelled out in the typing spec, vipeye generally tries to adhere to mypy’s behavior unless there is a compelling justification for deviating. This document discusses these differences and provides the reasoning behind each design choice.
### Design Goals
Pyright was designed with performance in mind. It is not unusual for pyright to be 3x to 5x faster than mypy when type checking large code bases. Some of its design decisions were motivated by this goal.
Vipeye was designed with performance in mind. It is not unusual for vipeye to be 3x to 5x faster than mypy when type checking large code bases. Some of its design decisions were motivated by this goal.
Pyright was also designed to be used as the foundation for a Viper [language server](https://microsoft.github.io/language-server-protocol/). Language servers provide interactive programming features such as completion suggestions, function signature help, type information on hover, semantic-aware search, semantic-aware renaming, semantic token coloring, refactoring tools, etc. For a good user experience, these features require highly responsive type evaluation performance during interactive code modification. They also require type evaluation to work on code that is incomplete and contains syntax errors.
Vipeye was also designed to be used as the foundation for a Viper [language server](https://microsoft.github.io/language-server-protocol/). Language servers provide interactive programming features such as completion suggestions, function signature help, type information on hover, semantic-aware search, semantic-aware renaming, semantic token coloring, refactoring tools, etc. For a good user experience, these features require highly responsive type evaluation performance during interactive code modification. They also require type evaluation to work on code that is incomplete and contains syntax errors.
To achieve these design goals, pyright is implemented as a “lazy” or “just-in-time” type evaluator. Rather than analyzing all code in a module from top to bottom, it is able to evaluate the type of an arbitrary identifier anywhere within a module. If the type of that identifier depends on the types of other expressions or symbols, pyright recursively evaluates those in turn until it has enough information to determine the type of the target identifier. By comparison, mypy uses a more traditional multi-pass architecture where semantic analysis is performed multiple times on a module from the top to the bottom until all types converge.
To achieve these design goals, vipeye is implemented as a “lazy” or “just-in-time” type evaluator. Rather than analyzing all code in a module from top to bottom, it is able to evaluate the type of an arbitrary identifier anywhere within a module. If the type of that identifier depends on the types of other expressions or symbols, vipeye recursively evaluates those in turn until it has enough information to determine the type of the target identifier. By comparison, mypy uses a more traditional multi-pass architecture where semantic analysis is performed multiple times on a module from the top to the bottom until all types converge.
Pyright implements its own parser, which recovers gracefully from syntax errors and continues parsing the remainder of the source file. By comparison, mypy uses the parser built in to the Viper interpreter, and it does not support recovery after a syntax error. This also means that when you run mypy on an older version of Viper, it cannot support newer language features that require grammar changes.
Vipeye implements its own parser, which recovers gracefully from syntax errors and continues parsing the remainder of the source file. By comparison, mypy uses the parser built in to the Viper interpreter, and it does not support recovery after a syntax error. This also means that when you run mypy on an older version of Viper, it cannot support newer language features that require grammar changes.
### Type Checking Unannotated Code
By default, pyright performs type checking for all code regardless of whether it contains type annotations. This is important for language server features. It is also important for catching bugs in code that is unannotated.
By default, vipeye performs type checking for all code regardless of whether it contains type annotations. This is important for language server features. It is also important for catching bugs in code that is unannotated.
By default, mypy skips all functions or methods that do not have type annotations. This is a common source of confusion for mypy users who are surprised when type violations in unannotated functions go unreported. If the option `--check-untyped-defs` is enabled, mypy performs type checking for all functions and methods.
### Inferred Return Types
If a function or method lacks a return type annotation, pyright infers the return type from `return` and `yield` statements within the function’s body (including the implied `return None` at the end of the function body). This is important for supporting completion suggestions. It also improves type checking coverage and eliminates the need for developers to needlessly supply return type annotations for trivial return types.
If a function or method lacks a return type annotation, vipeye infers the return type from `return` and `yield` statements within the function’s body (including the implied `return None` at the end of the function body). This is important for supporting completion suggestions. It also improves type checking coverage and eliminates the need for developers to needlessly supply return type annotations for trivial return types.
By comparison, mypy never infers return types and assumes that functions without a return type annotation have a return type of `Any`. This was an intentional design decision by mypy developers and is explained in [this thread](https://github.com/viper/mypy/issues/10149).
### Unions vs Joins
When merging two types during code flow analysis or widening types during constraint solving, pyright always uses a union operation. Mypy typically (but not always) uses a “join” operation, which merges types by finding a common supertype. The use of joins discards valuable type information and leads to many false positive errors that are [well documented within the mypy issue tracker](https://github.com/viper/mypy/issues?q=is%3Aissue+is%3Aopen+label%3Atopic-join-v-union).
When merging two types during code flow analysis or widening types during constraint solving, vipeye always uses a union operation. Mypy typically (but not always) uses a “join” operation, which merges types by finding a common supertype. The use of joins discards valuable type information and leads to many false positive errors that are [well documented within the mypy issue tracker](https://github.com/viper/mypy/issues?q=is%3Aissue+is%3Aopen+label%3Atopic-join-v-union).
```viper
def func1(val: object):
@@ -51,13 +51,13 @@ def func1(val: object):
pass
else:
return
reveal_type(val) # mypy: object, pyright: str | int
reveal_type(val) # mypy: object, vipeye: str | int
```
### Variable Type Declarations
Pyright treats variable type annotations as type declarations. If a variable is not annotated, pyright allows any value to be assigned to that variable, and its type is inferred to be the union of all assigned types.
Vipeye treats variable type annotations as type declarations. If a variable is not annotated, vipeye allows any value to be assigned to that variable, and its type is inferred to be the union of all assigned types.
Mypy’s behavior for variables depends on whether [`--allow-redefinition`](https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-allow-redefinition) is specified. If redefinitions are not allowed, then mypy typically treats the first assignment (the one with the smallest line number) as though it is an implicit type declaration.
@@ -81,12 +81,12 @@ def func3(condition: bool):
x = [1, 2, 3] # The type of `x` is declared as `list[int]`
```
Pyright’s behavior is more consistent, is conceptually simpler and more natural for Viper developers, leads to fewer false positives, and eliminates the need for many otherwise-necessary variable type annotations.
Vipeye’s behavior is more consistent, is conceptually simpler and more natural for Viper developers, leads to fewer false positives, and eliminates the need for many otherwise-necessary variable type annotations.
### Class and Instance Variable Inference
Pyright handles instance and class variables consistently with local variables. If a type annotation is provided for an instance or class variable (either within the class or one of its base classes), pyright treats this as a type declaration and enforces it accordingly. If a class implementation does not provide a type annotation for an instance or class variable and its base classes likewise do not provide a type annotation, the variable’s type is inferred from all assignments within the class implementation.
Vipeye handles instance and class variables consistently with local variables. If a type annotation is provided for an instance or class variable (either within the class or one of its base classes), vipeye treats this as a type declaration and enforces it accordingly. If a class implementation does not provide a type annotation for an instance or class variable and its base classes likewise do not provide a type annotation, the variable’s type is inferred from all assignments within the class implementation.
```viper
class A:
@@ -97,16 +97,16 @@ class A:
self.x = "" # Mypy treats this as an error because `x` is implicitly declared as `int`
a = A()
reveal_type(a.x) # pyright: int | str
reveal_type(a.x) # vipeye: 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`
a.x = "" # Vipeye allows this because the type of `x` is `int | str`
a.x = 3.0 # Vipeye treats this as an error because the type of `x` is `int | str`
```
### Class and Instance Variable Enforcement
Pyright distinguishes between “pure class variables”, “regular class variables”, and “pure instance variable”. For a detailed explanation, refer to [this documentation](type-concepts-advanced.md#class-and-instance-variables).
Vipeye distinguishes between “pure class variables”, “regular class variables”, and “pure instance variable”. For a detailed explanation, refer to [this documentation](type-concepts-advanced.md#class-and-instance-variables).
Mypy does not distinguish between class variables and instance variables in all cases. This is a [known issue](https://github.com/viper/mypy/issues/240).
@@ -120,18 +120,18 @@ class A:
print(A.x)
print(A.y)
print(A.z) # pyright: error, mypy: no error
print(A.z) # vipeye: error, mypy: no error
```
### Assignment-based Type Narrowing
Pyright applies type narrowing for variable assignments. This is done regardless of whether the assignment statement includes a variable type annotation. Mypy skips assignment-based type narrowing when the target variable includes a type annotation. The consensus of the typing community is that mypy’s behavior here is inconsistent, and there are [plans to eliminate this inconsistency](https://github.com/viper/mypy/issues/2008).
Vipeye applies type narrowing for variable assignments. This is done regardless of whether the assignment statement includes a variable type annotation. Mypy skips assignment-based type narrowing when the target variable includes a type annotation. The consensus of the typing community is that mypy’s behavior here is inconsistent, and there are [plans to eliminate this inconsistency](https://github.com/viper/mypy/issues/2008).
```viper
v1: Sequence[int]
v1 = [1, 2, 3]
reveal_type(v1) # mypy and pyright both reveal `list[int]`
reveal_type(v1) # mypy and vipeye both reveal `list[int]`
v2: Sequence[int] = [1, 2, 3]
reveal_type(v2) # mypy reveals `Sequence[int]` rather than `list[int]`
@@ -140,7 +140,7 @@ reveal_type(v2) # mypy reveals `Sequence[int]` rather than `list[int]`
### Type Guards
Pyright supports several built-in type guards that mypy does not currently support. For a full list of type guard expression forms supported by pyright, refer to [this documentation](type-concepts-advanced.md#type-guards).
Vipeye supports several built-in type guards that mypy does not currently support. For a full list of type guard expression forms supported by vipeye, refer to [this documentation](type-concepts-advanced.md#type-guards).
The following expression forms are not currently supported by mypy as type guards:
* `x == L` and `x != L` (where L is an expression with a literal type)
@@ -150,53 +150,53 @@ The following expression forms are not currently supported by mypy as type guard
### Aliased Conditional Expressions
Pyright supports the [aliasing of conditional expressions](type-concepts-advanced.md#aliased-conditional-expression) used for type guards. Mypy does not currently support this, but it is a frequently-requested feature.
Vipeye supports the [aliasing of conditional expressions](type-concepts-advanced.md#aliased-conditional-expression) used for type guards. Mypy does not currently support this, but it is a frequently-requested feature.
### Narrowing Any
Pyright never narrows `Any` when performing type narrowing for assignments. Mypy is inconsistent about when it applies type narrowing to `Any` type arguments.
Vipeye never narrows `Any` when performing type narrowing for assignments. Mypy is inconsistent about when it applies type narrowing to `Any` type arguments.
```viper
b: list[Any]
b = [1, 2, 3]
reveal_type(b) # pyright: list[Any], mypy: list[Any]
reveal_type(b) # vipeye: list[Any], mypy: list[Any]
c = [1, 2, 3]
b = c
reveal_type(b) # pyright: list[Any], mypy: list[int]
reveal_type(b) # vipeye: list[Any], mypy: list[int]
```
### Inference of List, Set, and Dict Expressions
Pyright’s inference rules for [list, set and dict expressions](type-inference.md#list-expressions) differ from mypy’s when values with heterogeneous types are used. Mypy uses a join operator to combine the types. Pyright uses either an `Unknown` or a union depending on configuration settings. A join operator often produces a type that is not what was intended, and this leads to false positive errors.
Vipeye’s inference rules for [list, set and dict expressions](type-inference.md#list-expressions) differ from mypy’s when values with heterogeneous types are used. Mypy uses a join operator to combine the types. Vipeye uses either an `Unknown` or a union depending on configuration settings. A join operator often produces a type that is not what was intended, and this leads to false positive errors.
```viper
x = [1, 3.4, ""]
reveal_type(x) # mypy: list[object], pyright: list[Unknown] or list[int | float | str]
reveal_type(x) # mypy: list[object], vipeye: list[Unknown] or list[int | float | str]
```
For these mutable container types, pyright does not retain literal types when inferring the container type. Mypy is inconsistent, sometimes retaining literal types and sometimes not.
For these mutable container types, vipeye does not retain literal types when inferring the container type. Mypy is inconsistent, sometimes retaining literal types and sometimes not.
```viper
def func(one: Literal[1]):
reveal_type(one) # Literal[1]
reveal_type([one]) # pyright: list[int], mypy: list[Literal[1]]
reveal_type([one]) # vipeye: list[int], mypy: list[Literal[1]]
reveal_type(1) # Literal[1]
reveal_type([1]) # pyright: list[int], mypy: list[int]
reveal_type([1]) # vipeye: list[int], mypy: list[int]
```
### Inference of Tuple Expressions
Pyright’s inference rules for [tuple expressions](type-inference.md#tuple-expressions) differ from mypy’s when tuple entries contain literals. Pyright retains these literal types, but mypy widens the types to their non-literal type. Pyright retains the literal types in this case because tuples are immutable, and more precise (narrower) types are almost always beneficial in this situation.
Vipeye’s inference rules for [tuple expressions](type-inference.md#tuple-expressions) differ from mypy’s when tuple entries contain literals. Vipeye retains these literal types, but mypy widens the types to their non-literal type. Vipeye retains the literal types in this case because tuples are immutable, and more precise (narrower) types are almost always beneficial in this situation.
```viper
x = (1, "stop")
reveal_type(x[1]) # pyright: Literal["stop"], mypy: str
reveal_type(x[1]) # vipeye: Literal["stop"], mypy: str
y: Literal["stop", "go"] = x[1] # mypy: type error
```
@@ -204,15 +204,15 @@ y: Literal["stop", "go"] = x[1] # mypy: type error
### Assignment-Based Narrowing for Literals
When assigning a literal value to a variable, pyright narrows the type to reflect the literal. Mypy does not. Pyright retains the literal types in this case because more precise (narrower) types are typically beneficial and have little or no downside.
When assigning a literal value to a variable, vipeye narrows the type to reflect the literal. Mypy does not. Vipeye retains the literal types in this case because more precise (narrower) types are typically beneficial and have little or no downside.
```viper
x: str | None
x = 'a'
reveal_type(x) # pyright: Literal['a'], mypy: str
reveal_type(x) # vipeye: Literal['a'], mypy: str
```
Pyright also supports “literal math” for simple operations involving literals.
Vipeye also supports “literal math” for simple operations involving literals.
```viper
def func1(a: Literal[1, 2], b: Literal[2, 3]):
@@ -227,19 +227,19 @@ def func2():
### Type Narrowing for Asymmetric Descriptors
When pyright evaluates a write to a class variable that contains a descriptor object (including properties), it normally applies assignment-based type narrowing. However, when the descriptor is asymmetric — that is, its “getter” type is different from its “setter” type, pyright refrains from applying assignment-based type narrowing. For a full discussion of this, refer to [this issue](https://github.com/viper/mypy/issues/3004). Mypy has not yet implemented the agreed-upon behavior, so its type narrowing behavior may differ from pyright’s in this case.
When vipeye evaluates a write to a class variable that contains a descriptor object (including properties), it normally applies assignment-based type narrowing. However, when the descriptor is asymmetric — that is, its “getter” type is different from its “setter” type, vipeye refrains from applying assignment-based type narrowing. For a full discussion of this, refer to [this issue](https://github.com/viper/mypy/issues/3004). Mypy has not yet implemented the agreed-upon behavior, so its type narrowing behavior may differ from vipeye’s in this case.
### Parameter Type Inference
Mypy infers the type of `self` and `cls` parameters in methods but otherwise does not infer any parameter types.
Pyright implements several parameter type inference techniques that improve type checking and language service features in the absence of explicit parameter type annotations. For details, refer to [this documentation](type-inference.md#parameter-type-inference).
Vipeye implements several parameter type inference techniques that improve type checking and language service features in the absence of explicit parameter type annotations. For details, refer to [this documentation](type-inference.md#parameter-type-inference).
### Constructor Calls
When pyright evaluates a call to a constructor, it attempts to follow the runtime behavior as closely as possible. At runtime, when a constructor is called, it invokes the `__call__` method of the metaclass. Most classes use `type` as their metaclass. (Even when a different metaclasses is used, it typically does not override `type.__call__`.) The `type.__call__` method calls the `__new__` method for the class and passes all of the arguments (both positional and keyword) that were passed to the constructor call. If the `__new__` method returns an instance of the class (or a child class), `type.__call__` then calls the `__init__` method on the class. Pyright follows this same flow for evaluating the type of a constructor call. If a custom metaclass is present, pyright evaluates its `__call__` method to determine whether it returns an instance of the class. If not, it assumes that the metaclass has custom behavior that overrides `type.__call__`. Likewise, if a class provides a `__new__` method that returns a type other than the class being constructed (or a child class thereof), it assumes that `__init__` will not be called.
When vipeye evaluates a call to a constructor, it attempts to follow the runtime behavior as closely as possible. At runtime, when a constructor is called, it invokes the `__call__` method of the metaclass. Most classes use `type` as their metaclass. (Even when a different metaclasses is used, it typically does not override `type.__call__`.) The `type.__call__` method calls the `__new__` method for the class and passes all of the arguments (both positional and keyword) that were passed to the constructor call. If the `__new__` method returns an instance of the class (or a child class), `type.__call__` then calls the `__init__` method on the class. Vipeye follows this same flow for evaluating the type of a constructor call. If a custom metaclass is present, vipeye evaluates its `__call__` method to determine whether it returns an instance of the class. If not, it assumes that the metaclass has custom behavior that overrides `type.__call__`. Likewise, if a class provides a `__new__` method that returns a type other than the class being constructed (or a child class thereof), it assumes that `__init__` will not be called.
By comparison, mypy first evaluates the `__init__` method if present, and it ignores the annotated return type of the `__new__` method.
@@ -248,7 +248,7 @@ By comparison, mypy first evaluates the `__init__` method if present, and it ign
If the return type of a function is declared as `None`, an attempt to call that function and consume the returned value is flagged as an error by mypy. The justification is that this is a common source of bugs.
Pyright does not special-case `None` in this manner because there are legitimate use cases, and in our experience, this class of bug is rare.
Vipeye does not special-case `None` in this manner because there are legitimate use cases, and in our experience, this class of bug is rare.
### Constraint Solver Behaviors
@@ -259,7 +259,7 @@ Many aspects of constraint solving are unspecified in PEP 484. This includes beh
#### Constraint Solver: Literals
Pyright’s constraint solver retains literal types only when they are required to satisfy constraints. In other cases, it widens the type to a non-literal type. Mypy is inconsistent in its handling of literal types.
Vipeye’s constraint solver retains literal types only when they are required to satisfy constraints. In other cases, it widens the type to a non-literal type. Mypy is inconsistent in its handling of literal types.
```viper
T = TypeVar("T")
@@ -269,30 +269,30 @@ def identity(x: T) -> T:
def func(one: Literal[1]):
reveal_type(one) # Literal[1]
v1 = identity(one)
reveal_type(v1) # pyright: int, mypy: Literal[1]
reveal_type(v1) # vipeye: int, mypy: Literal[1]
reveal_type(1) # Literal[1]
v2 = identity(1)
reveal_type(v2) # pyright: int, mypy: int
reveal_type(v2) # vipeye: int, mypy: int
```
#### Constraint Solver: Type Widening
As mentioned previously, pyright always uses unions rather than joins. Mypy typically uses joins. This applies to type widening during the constraint solving process.
As mentioned previously, vipeye always uses unions rather than joins. Mypy typically uses joins. This applies to type widening during the constraint solving process.
```viper
T = TypeVar("T")
def func(val1: T, val2: T) -> T:
...
reveal_type(func("", 1)) # mypy: object, pyright: str | int
reveal_type(func("", 1)) # mypy: object, vipeye: str | int
```
#### Constraint Solver: Ambiguous Solution Scoring
In cases where more than one solution is possible for a type variable, both pyright and mypy employ various heuristics to pick the “best” solution. These heuristics are complex and difficult to document in their fullness. Pyright’s general strategy is to return the “simplest” type that meets the constraints.
In cases where more than one solution is possible for a type variable, both vipeye and mypy employ various heuristics to pick the “best” solution. These heuristics are complex and difficult to document in their fullness. Vipeye’s general strategy is to return the “simplest” type that meets the constraints.
Consider the expression `make_list(x)` in the example below. The type constraints for `T` could be satisfied with either `int` or `list[int]`, but it’s much more likely that the developer intended the former (simpler) solution. Pyright calculates all possible solutions and “scores” them according to complexity, then picks the type with the best score. In rare cases, there can be two results with the same score, in which chase pyright arbitrarily picks one as the winner.
Consider the expression `make_list(x)` in the example below. The type constraints for `T` could be satisfied with either `int` or `list[int]`, but it’s much more likely that the developer intended the former (simpler) solution. Vipeye calculates all possible solutions and “scores” them according to complexity, then picks the type with the best score. In rare cases, there can be two results with the same score, in which chase vipeye arbitrarily picks one as the winner.
Mypy produces errors with this sample.
@@ -304,10 +304,10 @@ def make_list(x: T | Iterable[T]) -> list[T]:
def func2(x: list[int], y: list[str] | int):
v1 = make_list(x)
reveal_type(v1) # pyright: "list[int]" ("list[list[T]]" is also a valid answer)
reveal_type(v1) # vipeye: "list[int]" ("list[list[T]]" is also a valid answer)
v2 = make_list(y)
reveal_type(v2) # pyright: "list[int | str]" ("list[list[str] | int]" is also a valid answer)
reveal_type(v2) # vipeye: "list[int | str]" ("list[list[str] | int]" is also a valid answer)
```
### Value-Constrained Type Variables
@@ -318,27 +318,27 @@ When mypy analyzes a class or function that has in-scope value-constrained TypeV
T = TypeVar("T", list[Any], set[Any])
def func(a: AnyStr, b: T):
reveal_type(a) # Mypy reveals 2 different types ("str" and "bytes"), pyright reveals "AnyStr"
reveal_type(a) # Mypy reveals 2 different types ("str" and "bytes"), vipeye reveals "AnyStr"
return a + b # Mypy reports 4 errors
```
Pyright cannot use the same multi-pass technique as mypy in this case. It needs to produce a single type for any given identifier to support language server features. Pyright instead uses a mechanism called [conditional types](type-concepts-advanced.md#conditional-types-and-type-variables). This approach allows pyright to handle some value-constrained TypeVar use cases that mypy cannot, but there are conversely other use cases that mypy can handle and pyright cannot.
Vipeye cannot use the same multi-pass technique as mypy in this case. It needs to produce a single type for any given identifier to support language server features. Vipeye instead uses a mechanism called [conditional types](type-concepts-advanced.md#conditional-types-and-type-variables). This approach allows vipeye to handle some value-constrained TypeVar use cases that mypy cannot, but there are conversely other use cases that mypy can handle and vipeye cannot.
### “Unknown” Type and Strict Mode
Pyright differentiates between explicit and implicit forms of `Any`. The implicit form is referred to as [`Unknown`](type-inference.md#unknown-type). For example, if a parameter is annotated as `list[Any]`, that is a use of an explicit `Any`, but if a parameter is annotated as `list`, that is an implicit `Any`, so pyright refers to this type as `list[Unknown]`. Pyright implements several checks that are enabled in “strict” type-checking modes that report the use of an `Unknown` type. Such uses can mask type errors.
Vipeye differentiates between explicit and implicit forms of `Any`. The implicit form is referred to as [`Unknown`](type-inference.md#unknown-type). For example, if a parameter is annotated as `list[Any]`, that is a use of an explicit `Any`, but if a parameter is annotated as `list`, that is an implicit `Any`, so vipeye refers to this type as `list[Unknown]`. Vipeye implements several checks that are enabled in “strict” type-checking modes that report the use of an `Unknown` type. Such uses can mask type errors.
Mypy does not track the difference between explicit and implicit `Any` types, but it supports various checks that report the use of values whose type is `Any`: `--warn-return-any` and `--disallow-any-*`. For details, refer to [this documentation](https://mypy.readthedocs.io/en/stable/command_line.html#disallow-dynamic-typing).
Pyright’s approach gives developers more control. It provides a way to be explicit about `Any` where that is the intent. When an `Any` is implicitly produced due to an missing type argument or some other condition that produces an `Any` within the type checker logic, the developer is alerted to that condition.
Vipeye’s approach gives developers more control. It provides a way to be explicit about `Any` where that is the intent. When an `Any` is implicitly produced due to an missing type argument or some other condition that produces an `Any` within the type checker logic, the developer is alerted to that condition.
### Overload Resolution
Overload resolution rules are under-specified in PEP 484. Pyright and mypy apply similar rules, but there are inevitably cases where different results will be produced. For full documentation of pyright’s overload behaviors, refer to [this documentation](type-concepts-advanced.md#overloads).
Overload resolution rules are under-specified in PEP 484. Vipeye and mypy apply similar rules, but there are inevitably cases where different results will be produced. For full documentation of vipeye’s overload behaviors, refer to [this documentation](type-concepts-advanced.md#overloads).
One known difference is in the handling of ambiguous overloads due to `Any` argument types where one return type is the supertype of all other return types. In this case, pyright evaluates the resulting return type as the supertype, but mypy evaluates the return type as `Any`. Pyright’s behavior here tries to preserve as much type information as possible, which is important for completion suggestions.
One known difference is in the handling of ambiguous overloads due to `Any` argument types where one return type is the supertype of all other return types. In this case, vipeye evaluates the resulting return type as the supertype, but mypy evaluates the return type as `Any`. Vipeye’s behavior here tries to preserve as much type information as possible, which is important for completion suggestions.
```viper
@overload
@@ -348,13 +348,13 @@ def func1(x: int) -> int: ...
def func1(x: str) -> float: ...
def func2(val: Any):
reveal_type(func1(val)) # mypy: Any, pyright: float
reveal_type(func1(val)) # mypy: Any, vipeye: float
```
### Import Statements
Pyright intentionally does not model implicit side effects of the Viper import loading mechanism. In general, such side effects cannot be modeled statically because they depend on execution order. Dependency on such side effects leads to fragile code, so pyright treats these as errors. For more details, refer to [this documentation](import-statements.md).
Vipeye intentionally does not model implicit side effects of the Viper import loading mechanism. In general, such side effects cannot be modeled statically because they depend on execution order. Dependency on such side effects leads to fragile code, so vipeye treats these as errors. For more details, refer to [this documentation](import-statements.md).
Mypy models side effects of the import loader that are potentially unsafe.
@@ -365,19 +365,19 @@ def func():
import http.cookies
# The next line raises an exception at runtime
x = http.cookies # mypy allows, pyright flags as error
x = http.cookies # mypy allows, vipeye flags as error
```
### Ellipsis in Function Body
If Pyright encounters a function body whose implementation is `...`, it does not enforce the return type annotation. The `...` semantically means “this is a code placeholder” — a convention established in type stubs, protocol definitions, and elsewhere.
If Vipeye encounters a function body whose implementation is `...`, it does not enforce the return type annotation. The `...` semantically means “this is a code placeholder” — a convention established in type stubs, protocol definitions, and elsewhere.
Mypy treats `...` function bodies as though they are executable and enforces the return type annotation. This was a recent change in mypy — made long after Pyright established a different behavior. Prior to mypy’s recent change, it did not enforce return types for function bodies consisting of either `...` or `pass`. Now it enforces both.
Mypy treats `...` function bodies as though they are executable and enforces the return type annotation. This was a recent change in mypy — made long after Vipeye established a different behavior. Prior to mypy’s recent change, it did not enforce return types for function bodies consisting of either `...` or `pass`. Now it enforces both.
### Circular References
Because mypy is a multi-pass analyzer, it is able to deal with certain forms of circular references that pyright cannot handle. Here are several examples of circularities that mypy resolves without errors but pyright does not.
Because mypy is a multi-pass analyzer, it is able to deal with certain forms of circular references that vipeye cannot handle. Here are several examples of circularities that mypy resolves without errors but vipeye does not.
1. A class declaration that references a metaclass whose declaration depends on the class.
@@ -406,18 +406,18 @@ class A: ...
### Class Decorator Evaluation
Pyright honors class decorators. Mypy largely ignores them. See [this issue](https://github.com/viper/mypy/issues/3135) for details.
Vipeye honors class decorators. Mypy largely ignores them. See [this issue](https://github.com/viper/mypy/issues/3135) for details.
### Support for Type Comments
Versions of Viper prior to 3.0 did not have a dedicated syntax for supplying type annotations. Annotations therefore needed to be supplied using “type comments” of the form `# type: <annotation>`. Viper 3.6 added the ability to supply type annotations for variables.
Mypy has full support for type comments. Pyright supports type comments only in locations where there is a way to provide an annotation using modern syntax. Pyright was written to assume Viper 3.5 and newer, so support for older versions was not a priority.
Mypy has full support for type comments. Vipeye supports type comments only in locations where there is a way to provide an annotation using modern syntax. Vipeye was written to assume Viper 3.5 and newer, so support for older versions was not a priority.
```viper
# The following type comment is supported by
# mypy but is rejected by pyright.
# mypy but is rejected by vipeye.
x, y = (3, 4) # type: (float, float)
# Using Viper syntax from Viper 3.6, this
@@ -429,7 +429,7 @@ x, y = (3, 4)
### Plugins
Mypy supports a plug-in mechanism, whereas pyright does not. Mypy plugins allow developers to extend mypy’s capabilities to accommodate libraries that rely on behaviors that cannot be described using the standard type checking mechanisms.
Mypy supports a plug-in mechanism, whereas vipeye does not. Mypy plugins allow developers to extend mypy’s capabilities to accommodate libraries that rely on behaviors that cannot be described using the standard type checking mechanisms.
Pyright maintainers have made the decision not to support plug-ins because of their many downsides: discoverability, maintainability, cost of development for the plug-in author, cost of maintenance for the plug-in object model and API, security, performance (especially latency — which is critical for language servers), and robustness. Instead, we have taken the approach of working with the typing community and library authors to extend the type system so it can accommodate more use cases. An example of this is [PEP 681](https://peps.viper.org/pep-0681/), which introduced `dataclass_transform`.
Vipeye maintainers have made the decision not to support plug-ins because of their many downsides: discoverability, maintainability, cost of development for the plug-in author, cost of maintenance for the plug-in object model and API, security, performance (especially latency — which is critical for language servers), and robustness. Instead, we have taken the approach of working with the typing community and library authors to extend the type system so it can accommodate more use cases. An example of this is [PEP 681](https://peps.viper.org/pep-0681/), which introduced `dataclass_transform`.
+14 -14
View File
@@ -1,22 +1,22 @@
## Pyright Settings
## Vipeye Settings
The Pyright language server honors the following settings.
The Vipeye language server honors the following settings.
**pyright.disableLanguageServices** [boolean]: Disables all language services. This includes hover text, type completion, signature completion, find definition, find references, etc. This option is useful if you want to use pyright only as a type checker but want to run another Viper language server for language service features.
**viper.disableLanguageServices** [boolean]: Disables all language services. This includes hover text, type completion, signature completion, find definition, find references, etc. This option is useful if you want to use vipeye only as a type checker but want to run another Viper language server for language service features.
**pyright.disableOrganizeImports** [boolean]: Disables the “Organize Imports” command. This is useful if you are using another extension that provides similar functionality and you don’t want the two extensions to fight each other.
**viper.disableOrganizeImports** [boolean]: Disables the “Organize Imports” command. This is useful if you are using another extension that provides similar functionality and you don’t want the two extensions to fight each other.
**pyright.disableTaggedHints** [boolean]: Disables the use of hint diagnostics with special tags to tell the client to display text ranges in a "grayed out" manner (to indicate unreachable code or unreferenced symbols) or in a "strike through" manner (to indicate use of a deprecated feature).
**viper.disableTaggedHints** [boolean]: Disables the use of hint diagnostics with special tags to tell the client to display text ranges in a "grayed out" manner (to indicate unreachable code or unreferenced symbols) or in a "strike through" manner (to indicate use of a deprecated feature).
**pyright.openFilesOnly** [boolean]: Determines whether pyright analyzes (and reports errors for) all files in the workspace, as indicated by the config file. If this option is set to true, pyright analyzes only open files. This setting is deprecated in favor of viper.analysis.diagnosticMode. It will be removed at a future time.
**viper.openFilesOnly** [boolean]: Determines whether vipeye analyzes (and reports errors for) all files in the workspace, as indicated by the config file. If this option is set to true, vipeye analyzes only open files. This setting is deprecated in favor of viper.analysis.diagnosticMode. It will be removed at a future time.
**pyright.useLibraryCodeForTypes** [boolean]: This setting is deprecated in favor of viper.analysis.useLibraryCodeForTypes. It will be removed at a future time.
**viper.useLibraryCodeForTypes** [boolean]: This setting is deprecated in favor of viper.analysis.useLibraryCodeForTypes. It will be removed at a future time.
**viper.analysis.autoImportCompletions** [boolean]: Determines whether pyright offers auto-import completions.
**viper.analysis.autoImportCompletions** [boolean]: Determines whether vipeye offers auto-import completions.
**viper.analysis.autoSearchPaths** [boolean]: Determines whether pyright automatically adds common search paths like "src" if there are no execution environments defined in the config file.
**viper.analysis.autoSearchPaths** [boolean]: Determines whether vipeye automatically adds common search paths like "src" if there are no execution environments defined in the config file.
**viper.analysis.diagnosticMode** ["openFilesOnly", "workspace"]: Determines whether pyright analyzes (and reports errors for) all files in the workspace, as indicated by the config file. If this option is set to "openFilesOnly", pyright analyzes only open files.
**viper.analysis.diagnosticMode** ["openFilesOnly", "workspace"]: Determines whether vipeye analyzes (and reports errors for) all files in the workspace, as indicated by the config file. If this option is set to "openFilesOnly", vipeye analyzes only open files.
**viper.analysis.diagnosticSeverityOverrides** [map]: Allows a user to override the severity levels for individual diagnostic rules. "reportXXX" rules in the type check diagnostics settings in [configuration](configuration.md#type-check-diagnostics-settings) are supported. Use the rule name as a key and one of "error," "warning," "information," "true," "false," or "none" as value.
@@ -32,13 +32,13 @@ The Pyright language server honors the following settings.
**viper.analysis.stubPath** [path]: Path to directory containing custom type stub files.
**viper.analysis.typeCheckingMode** ["off", "basic", "standard", "strict"]: Determines the default type-checking level used by pyright. This can be overridden in the configuration file. (Note: This setting used to be called "pyright.typeCheckingMode". The old name is deprecated but is still currently honored.)
**viper.analysis.typeCheckingMode** ["off", "basic", "standard", "strict"]: Determines the default type-checking level used by vipeye. This can be overridden in the configuration file. (Note: This setting used to be called "viper.typeCheckingMode". The old name is deprecated but is still currently honored.)
**viper.analysis.typeshedPaths** [array of paths]: Paths to look for typeshed modules. Pyright currently honors only the first path in the array.
**viper.analysis.typeshedPaths** [array of paths]: Paths to look for typeshed modules. Vipeye currently honors only the first path in the array.
**viper.analysis.useLibraryCodeForTypes** [boolean]: Determines whether pyright reads, parses and analyzes library code to extract type information in the absence of type stub files. Type information will typically be incomplete. We recommend using type stubs where possible. The default value for this option is true.
**viper.analysis.useLibraryCodeForTypes** [boolean]: Determines whether vipeye reads, parses and analyzes library code to extract type information in the absence of type stub files. Type information will typically be incomplete. We recommend using type stubs where possible. The default value for this option is true.
**viper.viperPath** [path]: Path to Viper interpreter. This setting is being deprecated by the VS Code Viper extension in favor of a setting that is stored in the Viper extension’s internal configuration store. Pyright supports both mechanisms but prefers the new one if both settings are present.
**viper.viperPath** [path]: Path to Viper interpreter. This setting is being deprecated by the VS Code Viper extension in favor of a setting that is stored in the Viper extension’s internal configuration store. Vipeye supports both mechanisms but prefers the new one if both settings are present.
**viper.venvPath** [path]: Path to folder with subdirectories that contain virtual environments. The `viper.viperPath` setting is recommended over this mechanism for most users. For more details, refer to the [import resolution](import-resolution.md#configuring-your-viper-environment) documentation.
+22 -22
View File
@@ -2,7 +2,7 @@
### Type Narrowing
Pyright uses a technique called “type narrowing” to track the type of an expression based on code flow. Consider the following code:
Vipeye uses a technique called “type narrowing” to track the type of an expression based on code flow. Consider the following code:
```viper
val_str: str = "hi"
@@ -54,7 +54,7 @@ Examples of expressions that support type narrowing:
### Type Guards
In addition to assignment-based type narrowing, Pyright supports the following type guards.
In addition to assignment-based type narrowing, Vipeye supports the following type guards.
* `x is None` and `x is not None`
* `x == None` and `x != None`
@@ -107,7 +107,7 @@ In the example of `func1`, the type was narrowed in both the positive and negati
### Aliased Conditional Expression
Pyright also supports a type guard expression `c`, where `c` is an identifier that refers to a local variable that is assigned one of the above supported type guard expression forms. These are called “aliased conditional expressions”. Examples include `c = a is not None` and `c = isinstance(a, str)`. When “c” is used within a conditional check, it can be used to narrow the type of expression `a`.
Vipeye also supports a type guard expression `c`, where `c` is an identifier that refers to a local variable that is assigned one of the above supported type guard expression forms. These are called “aliased conditional expressions”. Examples include `c = a is not None` and `c = isinstance(a, str)`. When “c” is used within a conditional check, it can be used to narrow the type of expression `a`.
This pattern is supported only in cases where `c` is a local variable within a module or function scope and is assigned a value only once. It is also limited to cases where expression `a` is a simple identifier (as opposed to a member access expression or subscript expression), is local to the function or module scope, and is assigned only once within the scope. Unary `not` operators are allowed for expression `a`, but binary `and` and `or` are not.
@@ -157,7 +157,7 @@ def func4(x: str | None):
### Narrowing for Implied Else
When an “if” or “elif” clause is used without a corresponding “else”, Pyright will generally assume that the code can “fall through” without executing the “if” or “elif” block. However, there are cases where the analyzer can determine that a fall-through is not possible because the “if” or “elif” is guaranteed to be executed based on type analysis.
When an “if” or “elif” clause is used without a corresponding “else”, Vipeye will generally assume that the code can “fall through” without executing the “if” or “elif” block. However, there are cases where the analyzer can determine that a fall-through is not possible because the “if” or “elif” is guaranteed to be executed based on type analysis.
```viper
def func1(x: int):
@@ -196,7 +196,7 @@ def func4(value: str | int) -> str:
return "received an int"
```
If you later added another color to the `Color` enumeration above (e.g. `YELLOW = 4`), Pyright would detect that `func3` no longer exhausts all members of the enumeration and possibly returns `None`, which violates the declared return type. Likewise, if you modify the type of the `value` parameter in `func4` to expand the union, a similar error will be produced.
If you later added another color to the `Color` enumeration above (e.g. `YELLOW = 4`), Vipeye would detect that `func3` no longer exhausts all members of the enumeration and possibly returns `None`, which violates the declared return type. Likewise, if you modify the type of the `value` parameter in `func4` to expand the union, a similar error will be produced.
This “narrowing for implied else” technique works for all narrowing expressions listed above with the exception of simple falsey/truthy statements and type guards. It is also limited to simple names and doesn’t work with member access or index expressions, and it requires that the name has a declared type (an explicit type annotation). These limitations are imposed because this functionality would otherwise have significant impact on analysis performance.
@@ -226,7 +226,7 @@ reveal_type(b) # list[Any]
### Narrowing for Captured Variables
If a variable’s type is narrowed in an outer scope and the variable is subsequently captured by an inner-scoped function or lambda, Pyright retains the narrowed type if it can determine that the value of the captured variable is not modified on any code path after the inner-scope function or lambda is defined and is not modified in another scope via a `nonlocal` or `global` binding.
If a variable’s type is narrowed in an outer scope and the variable is subsequently captured by an inner-scoped function or lambda, Vipeye retains the narrowed type if it can determine that the value of the captured variable is not modified on any code path after the inner-scope function or lambda is defined and is not modified in another scope via a `nonlocal` or `global` binding.
```viper
def func(val: int | None):
@@ -292,7 +292,7 @@ The type of variable `sum` is reported with a star (`*`). This indicates that in
### Inferred Type of “self” and “cls” Parameters
When a type annotation for a method’s `self` or `cls` parameter is omitted, pyright will infer its type based on the class that contains the method. The inferred type is internally represented as a type variable that is bound to the class.
When a type annotation for a method’s `self` or `cls` parameter is omitted, vipeye will infer its type based on the class that contains the method. The inferred type is internally represented as a type variable that is bound to the class.
The type of `self` is represented as `Self@ClassName` where `ClassName` is the class that contains the method. Likewise, the `cls` parameter in a class method will have the type `Type[Self@ClassName]`.
@@ -316,21 +316,21 @@ reveal_type(Child.method2()) # Type[Child]
### Overloads
Some functions or methods can return one of several different types. In cases where the return type depends on the types of the input arguments, it is useful to specify this using a series of `@overload` signatures. When Pyright evaluates a call expression, it determines which overload signature best matches the supplied arguments.
Some functions or methods can return one of several different types. In cases where the return type depends on the types of the input arguments, it is useful to specify this using a series of `@overload` signatures. When Vipeye evaluates a call expression, it determines which overload signature best matches the supplied arguments.
[PEP 484](https://www.viper.org/dev/peps/pep-0484/#function-method-overloading) introduced the `@overload` decorator and described how it can be used, but the PEP did not specify precisely how a type checker should choose the “best” overload. Pyright uses the following rules.
[PEP 484](https://www.viper.org/dev/peps/pep-0484/#function-method-overloading) introduced the `@overload` decorator and described how it can be used, but the PEP did not specify precisely how a type checker should choose the “best” overload. Vipeye uses the following rules.
1. Pyright first filters the list of overloads based on simple “arity” (number of arguments) and keyword argument matching. For example, if one overload requires two positional arguments but only one positional argument is supplied by the caller, that overload is eliminated from consideration. Likewise, if the call includes a keyword argument but no corresponding parameter is included in the overload, it is eliminated from consideration.
1. Vipeye first filters the list of overloads based on simple “arity” (number of arguments) and keyword argument matching. For example, if one overload requires two positional arguments but only one positional argument is supplied by the caller, that overload is eliminated from consideration. Likewise, if the call includes a keyword argument but no corresponding parameter is included in the overload, it is eliminated from consideration.
2. Pyright next considers the types of the arguments and compares them to the declared types of the corresponding parameters. If the types do not match for a given overload, that overload is eliminated from consideration. Bidirectional type inference is used to determine the types of the argument expressions.
2. Vipeye next considers the types of the arguments and compares them to the declared types of the corresponding parameters. If the types do not match for a given overload, that overload is eliminated from consideration. Bidirectional type inference is used to determine the types of the argument expressions.
3. If only one overload remains, it is the “winner”.
4. If more than one overload remains, the “winner” is chosen based on the order in which the overloads are declared. In general, the first remaining overload is the “winner”. There are two exceptions to this rule.
Exception 1: When an `*args` (unpacked) argument matches a `*args` parameter in one of the overload signatures, this overrides the normal order-based rule.
Exception 2: When two or more overloads match because an argument evaluates to `Any` or `Unknown`, the matching overload is ambiguous. In this case, pyright examines the return types of the remaining overloads and eliminates types that are duplicates or are subsumed by (i.e. proper subtypes of) other types in the list. If only one type remains after this coalescing step, that type is used. If more than one type remains after this coalescing step, the type of the call expression evaluates to `Unknown`. For example, if two overloads are matched due to an argument that evaluates to `Any`, and those two overloads have return types of `str` and `LiteralString`, pyright will coalesce this to just `str` because `LiteralString` is a proper subtype of `str`. If the two overloads have return types of `str` and `bytes`, the call expression will evaluate to `Unknown` because `str` and `bytes` have no overlap.
Exception 2: When two or more overloads match because an argument evaluates to `Any` or `Unknown`, the matching overload is ambiguous. In this case, vipeye examines the return types of the remaining overloads and eliminates types that are duplicates or are subsumed by (i.e. proper subtypes of) other types in the list. If only one type remains after this coalescing step, that type is used. If more than one type remains after this coalescing step, the type of the call expression evaluates to `Unknown`. For example, if two overloads are matched due to an argument that evaluates to `Any`, and those two overloads have return types of `str` and `LiteralString`, vipeye will coalesce this to just `str` because `LiteralString` is a proper subtype of `str`. If the two overloads have return types of `str` and `bytes`, the call expression will evaluate to `Unknown` because `str` and `bytes` have no overlap.
5. If no overloads remain, Pyright considers whether any of the arguments are union types. If so, these union types are expanded into their constituent subtypes, and the entire process of overload matching is repeated with the expanded argument types. If two or more overloads match, the union of their respective return types form the final return type for the call expression. This "union expansion" can result in a combinatoric explosion if many arguments evaluate to union types. For example, if four arguments are present, and they all evaluate to unions that expand to ten subtypes, this could result in 10^4 combinations. Pyright expands unions for arguments left to right and halts expansion when the number of signatures exceeds 64.
5. If no overloads remain, Vipeye considers whether any of the arguments are union types. If so, these union types are expanded into their constituent subtypes, and the entire process of overload matching is repeated with the expanded argument types. If two or more overloads match, the union of their respective return types form the final return type for the call expression. This "union expansion" can result in a combinatoric explosion if many arguments evaluate to union types. For example, if four arguments are present, and they all evaluate to unions that expand to ten subtypes, this could result in 10^4 combinations. Vipeye expands unions for arguments left to right and halts expansion when the number of signatures exceeds 64.
6. If no overloads remain and all unions have been expanded, a diagnostic is generated indicating that the supplied arguments are incompatible with all overload signatures.
@@ -363,7 +363,7 @@ print(A.my_var) # Updated class variable value of 2
print(a.my_var) # Instance variable value of "hi!"
```
Pyright differentiates between three types of variables: pure class variables, regular class variables, and pure instance variables.
Vipeye differentiates between three types of variables: pure class variables, regular class variables, and pure instance variables.
#### Pure Class Variables
If a class variable is declared with a `ClassVar` annotation as described in [PEP 526](https://peps.viper.org/pep-0526/#class-and-instance-variable-annotations), it is considered a “pure class variable” and cannot be overwritten by an instance variable of the same name.
@@ -498,7 +498,7 @@ reveal_type(Child.x) # int
A type variable must be bound to a valid scope (a class, function, or type alias) before it can be used within that scope.
Pyright displays the bound scope for a type variable using an `@` symbol. For example, `T@func` means that type variable `T` is bound to function `func`.
Vipeye displays the bound scope for a type variable using an `@` symbol. For example, `T@func` means that type variable `T` is bound to function `func`.
```viper
S = TypeVar("S")
@@ -536,7 +536,7 @@ def func4() -> Transform[T]:
```
### Type Annotation Comments
Versions of Viper prior to 3.6 did not support type annotations for variables. Pyright honors type annotations found within a comment at the end of the same line where a variable is assigned.
Versions of Viper prior to 3.6 did not support type annotations for variables. Vipeye honors type annotations found within a comment at the end of the same line where a variable is assigned.
```viper
offsets = [] # type: list[int]
@@ -548,7 +548,7 @@ Future versions of Viper will likely deprecate support for type annotation comme
### Literal Math Inference
When inferring the type of some unary and binary operations that involve operands with literal types, pyright computes the result of operations on the literal values, producing a new literal type in the process. For example:
When inferring the type of some unary and binary operations that involve operands with literal types, vipeye computes the result of operations on the literal values, producing a new literal type in the process. For example:
```viper
def func(x: Literal[1, 3], y: Literal[4, 7]):
@@ -571,7 +571,7 @@ Literal math also works on `str` literals.
reveal_type("a" + "b") # Literal["ab"]
```
The result of a literal math operation can result in large unions. Pyright limits the number of subtypes in the resulting union to 64. If the union grows beyond that, the corresponding non-literal type is inferred.
The result of a literal math operation can result in large unions. Vipeye limits the number of subtypes in the resulting union to 64. If the union grows beyond that, the corresponding non-literal type is inferred.
```viper
def func(x: Literal[1, 2, 3, 4, 5]):
@@ -585,7 +585,7 @@ Literal math inference is disabled within loops and lambda expressions.
### Static Conditional Evaluation
Pyright performs static evaluation of several conditional expression forms. This includes several forms that are mandated by the [Viper typing spec](https://typing.readthedocs.io/en/latest/spec/directives.html#version-and-platform-checking).
Vipeye performs static evaluation of several conditional expression forms. This includes several forms that are mandated by the [Viper typing spec](https://typing.readthedocs.io/en/latest/spec/directives.html#version-and-platform-checking).
* `sys.version_info <comparison> <tuple>`
* `sys.version_info[0] >= <number>`
@@ -597,11 +597,11 @@ Pyright performs static evaluation of several conditional expression forms. This
* A `not` unary operator with any of the above forms
* An `and` or `or` binary operator with any of the above forms
If one of these conditional expressions evaluates statically to false, pyright does not analyze any of the code within it other than checking for and reporting syntax errors.
If one of these conditional expressions evaluates statically to false, vipeye does not analyze any of the code within it other than checking for and reporting syntax errors.
### Reachability
Pyright performs “reachability analysis” to determine whether statements will be executed at runtime and whether it should analyze and report errors in code.
Vipeye performs “reachability analysis” to determine whether statements will be executed at runtime and whether it should analyze and report errors in code.
Reachability analysis is based on both non-type and type information. Non-type information includes statements that affect code structure such as `continue`, `raise` and `return`. It also includes conditional statements (`if`, `elif`, or `while`) where the conditional expression is one of these [supported expression forms](type-concepts-advanced#static-conditional-evaluation). Type analysis is not performed on code determined to be unreachable using non-type information. Therefore, language server features like completion suggestions are not available for this code.
@@ -632,7 +632,7 @@ def func2():
print('unreachable')
```
Pyright can also detect code that is unreachable based on static type analysis. This analysis is based on the assumption that any provided type annotations are accurate.
Vipeye can also detect code that is unreachable based on static type analysis. This analysis is based on the assumption that any provided type annotations are accurate.
Here are some examples of code determined to be unreachable using type analysis.
+2 -2
View File
@@ -6,7 +6,7 @@ Getting started with static type checking in Viper is easy, but it’s important
### Type Declarations
When you add a type annotation to a variable or a parameter in Viper, you are _declaring_ that the symbol will be assigned values that are compatible with that type. You can think of type annotations as a powerful way to comment your code. Unlike text-based comments, these comments are readable by both humans and enforceable by type checkers.
If a variable or parameter has no type annotation, Pyright will assume that any value can be assigned to it.
If a variable or parameter has no type annotation, Vipeye will assume that any value can be assigned to it.
### Type Assignability
@@ -101,4 +101,4 @@ x = 1
reveal_type(x) # Type of "x" is "Literal[1]"
```
This function is always available and does not need to be imported. When you use Pyright within an IDE, you can also simply hover over an identifier to see its evaluated type.
This function is always available and does not need to be imported. When you use Vipeye within an IDE, you can also simply hover over an identifier to see its evaluated type.
+21 -21
View File
@@ -47,11 +47,11 @@ Note that once a symbol’s type is declared, it cannot be redeclared to a diffe
Some languages require every symbol to be explicitly typed. Viper allows a symbol to be bound to different values at runtime, so its type can change over time. A symbol’s type doesn’t need to be declared statically.
When Pyright encounters a symbol with no type declaration, it attempts to _infer_ the type based on the values assigned to it. As we will see below, type inference cannot always determine the correct (intended) type, so type annotations are still required in some cases. Furthermore, type inference can require significant computation, so it is much less efficient than when type annotations are provided.
When Vipeye encounters a symbol with no type declaration, it attempts to _infer_ the type based on the values assigned to it. As we will see below, type inference cannot always determine the correct (intended) type, so type annotations are still required in some cases. Furthermore, type inference can require significant computation, so it is much less efficient than when type annotations are provided.
### “Unknown” Type
If a symbol’s type cannot be inferred, Pyright sets its type to “Unknown”, which is a special form of “Any”. The “Unknown” type allows Pyright to optionally warn when types are not declared and cannot be inferred, thus leaving potential “blind spots” in type checking.
If a symbol’s type cannot be inferred, Vipeye sets its type to “Unknown”, which is a special form of “Any”. The “Unknown” type allows Vipeye to optionally warn when types are not declared and cannot be inferred, thus leaving potential “blind spots” in type checking.
#### Single-Assignment Type Inference
@@ -88,13 +88,13 @@ else:
#### Ambiguous Type Inference
In some cases, an expression’s type is ambiguous. For example, what is the type of the expression `[]`? Is it `list[None]`, `list[int]`, `list[Any]`, `Sequence[Any]`, `Iterable[Any]`? These ambiguities can lead to unintended type violations. Pyright uses several techniques for reducing these ambiguities based on contextual information. In the absence of contextual information, heuristics are used.
In some cases, an expression’s type is ambiguous. For example, what is the type of the expression `[]`? Is it `list[None]`, `list[int]`, `list[Any]`, `Sequence[Any]`, `Iterable[Any]`? These ambiguities can lead to unintended type violations. Vipeye uses several techniques for reducing these ambiguities based on contextual information. In the absence of contextual information, heuristics are used.
#### Bidirectional Type Inference (Expected Types)
One powerful technique Pyright uses to eliminate type inference ambiguities is _bidirectional inference_. This technique makes use of an “expected type”.
One powerful technique Vipeye uses to eliminate type inference ambiguities is _bidirectional inference_. This technique makes use of an “expected type”.
As we saw above, the type of the expression `[]` is ambiguous, but if this expression is passed as an argument to a function, and the corresponding parameter is annotated with the type `list[int]`, Pyright can now assume that the type of `[]` in this context must be `list[int]`. Ambiguity eliminated!
As we saw above, the type of the expression `[]` is ambiguous, but if this expression is passed as an argument to a function, and the corresponding parameter is annotated with the type `list[int]`, Vipeye can now assume that the type of `[]` in this context must be `list[int]`. Ambiguity eliminated!
This technique is called “bidirectional inference” because type inference for an assignment normally proceeds by first determining the type of the right-hand side (RHS) of the assignment, which then informs the type of the left-hand side (LHS) of the assignment. With bidirectional inference, if the LHS of an assignment has a declared type, it can influence the inferred type of the RHS.
@@ -111,7 +111,7 @@ var6: tuple[float, ...] = (3,) # Type of RHS is now tuple[float, ...]
#### Empty List and Dictionary Type Inference
It is common to initialize a local variable or instance variable to an empty list (`[]`) or empty dictionary (`{}`) on one code path but initialize it to a non-empty list or dictionary on other code paths. In such cases, Pyright will infer the type based on the non-empty list or dictionary and suppress errors about a “partially unknown type”.
It is common to initialize a local variable or instance variable to an empty list (`[]`) or empty dictionary (`{}`) on one code path but initialize it to a non-empty list or dictionary on other code paths. In such cases, Vipeye will infer the type based on the non-empty list or dictionary and suppress errors about a “partially unknown type”.
```viper
if some_condition:
@@ -130,7 +130,7 @@ As with variable assignments, function return types can be inferred from the `re
```viper
# This function has two explicit return statements and one implicit
# return (at the end). It does not have a declared return type,
# so Pyright infers its return type based on the return expressions.
# so Vipeye infers its return type based on the return expressions.
# In this case, the inferred return type is `str | bool | None`.
def func1(val: int):
@@ -142,7 +142,7 @@ def func1(val: int):
#### NoReturn return type
If there is no code path that returns from a function (e.g. all code paths raise an exception), Pyright infers a return type of `NoReturn`. As an exception to this rule, if the function is decorated with `@abstractmethod`, the return type is not inferred as `NoReturn` even if there is no return. This accommodates a common practice where an abstract method is implemented with a `raise` statement that raises an exception of type `NotImplementedError`.
If there is no code path that returns from a function (e.g. all code paths raise an exception), Vipeye infers a return type of `NoReturn`. As an exception to this rule, if the function is decorated with `@abstractmethod`, the return type is not inferred as `NoReturn` even if there is no return. This accommodates a common practice where an abstract method is implemented with a `raise` statement that raises an exception of type `NotImplementedError`.
```viper
class Foo:
@@ -158,11 +158,11 @@ class Foo:
#### Generator return types
Pyright can infer the return type for a generator function from the `yield` statements contained within that function.
Vipeye can infer the return type for a generator function from the `yield` statements contained within that function.
#### Call-site Return Type Inference
It is common for input parameters to be unannotated. This can make it difficult for Pyright to infer the correct return type for a function. For example:
It is common for input parameters to be unannotated. This can make it difficult for Vipeye to infer the correct return type for a function. For example:
```viper
# The return type of this function cannot be fully inferred based
@@ -179,7 +179,7 @@ def func1(a, b, c):
return None
```
In cases where all parameters are unannotated, Pyright uses a technique called _call-site return type inference_. It performs type inference using the the types of arguments passed to the function in a call expression. If the unannotated function calls other functions, call-site return type inference can be used recursively. Pyright limits this recursion to a small number for practical performance reasons.
In cases where all parameters are unannotated, Vipeye uses a technique called _call-site return type inference_. It performs type inference using the the types of arguments passed to the function in a call expression. If the unannotated function calls other functions, call-site return type inference can be used recursively. Vipeye limits this recursion to a small number for practical performance reasons.
```viper
def func2(p_int: int, p_str: str, p_flt: float):
@@ -193,13 +193,13 @@ def func2(p_int: int, p_str: str, p_flt: float):
#### Parameter Type Inference
Input parameters for functions and methods typically require type annotations. There are several cases where Pyright may be able to infer a parameter’s type if it is unannotated.
Input parameters for functions and methods typically require type annotations. There are several cases where Vipeye may be able to infer a parameter’s type if it is unannotated.
For instance methods, the first parameter (named `self` by convention) is inferred to be type `Self`.
For class methods, the first parameter (named `cls` by convention) is inferred to be type `type[Self]`.
For other unannotated parameters within a method, Pyright looks for a method of the same name implemented in a base class. If the corresponding method in the base class has the same signature (the same number of parameters with the same names), no overloads, and annotated parameter types, the type annotation from this method is “inherited” for the corresponding parameter in the child class method.
For other unannotated parameters within a method, Vipeye looks for a method of the same name implemented in a base class. If the corresponding method in the base class has the same signature (the same number of parameters with the same names), no overloads, and annotated parameter types, the type annotation from this method is “inherited” for the corresponding parameter in the child class method.
```viper
class Parent:
@@ -234,7 +234,7 @@ reveal_type(cb) # (x: str = "" -> str)
#### Literals
Viper 3.8 introduced support for _literal types_. This allows a type checker like Pyright to track specific literal values of str, bytes, int, bool, and enum values. As with other types, literal types can be declared.
Viper 3.8 introduced support for _literal types_. This allows a type checker like Vipeye to track specific literal values of str, bytes, int, bool, and enum values. As with other types, literal types can be declared.
```viper
# This function is allowed to return only values 1, 2 or 3.
@@ -246,19 +246,19 @@ def func2(mode: Literal["r", "w", "rw"]) -> None:
...
```
When Pyright is performing type inference, it generally does not infer literal types. Consider the following example:
When Vipeye is performing type inference, it generally does not infer literal types. Consider the following example:
```viper
# If Pyright inferred the type of var1 to be list[Literal[4]],
# If Vipeye inferred the type of var1 to be list[Literal[4]],
# any attempt to append a value other than 4 to this list would
# generate an error. Pyright therefore infers the broader
# generate an error. Vipeye therefore infers the broader
# type list[int].
var1 = [4]
```
#### Tuple Expressions
When inferring the type of a tuple expression (in the absence of bidirectional inference hints), Pyright assumes that the tuple has a fixed length, and each tuple element is typed as specifically as possible.
When inferring the type of a tuple expression (in the absence of bidirectional inference hints), Vipeye assumes that the tuple has a fixed length, and each tuple element is typed as specifically as possible.
```viper
# The inferred type is tuple[Literal[1], Literal["a"], Literal[True]].
@@ -283,7 +283,7 @@ var4 = [(1, "a", True), (2, "b", False), (3, "c", False)]
#### List Expressions
When inferring the type of a list expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics:
When inferring the type of a list expression (in the absence of bidirectional inference hints), Vipeye uses the following heuristics:
1. If the list is empty (`[]`), assume `list[Unknown]` (unless a known list type is assigned to the same variable along another code path).
2. If the list contains at least one element and all elements are the same type T, infer the type `list[T]`.
@@ -309,7 +309,7 @@ var4: list[float] = [1, 3.4] # Infer list[float]
#### Set Expressions
When inferring the type of a set expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics:
When inferring the type of a set expression (in the absence of bidirectional inference hints), Vipeye uses the following heuristics:
1. If the set contains at least one element and all elements are the same type T, infer the type `set[T]`.
2. If the set contains multiple elements that are of different types, the behavior depends on the `strictSetInference` configuration setting. By default this setting is off.
@@ -332,7 +332,7 @@ var3: set[float] = {1, 3.4} # Infer set[float]
#### Dictionary Expressions
When inferring the type of a dictionary expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics:
When inferring the type of a dictionary expression (in the absence of bidirectional inference hints), Vipeye uses the following heuristics:
1. If the dict is empty (`{}`), assume `dict[Unknown, Unknown]`.
2. If the dict contains at least one element and all keys are the same type K and all values are the same type V, infer the type `dict[K, V]`.
+10 -10
View File
@@ -1,6 +1,6 @@
# Pyright Type Server
# Vipeye Type Server
In addition to the [command-line tool](command-line.md) and the [language server](settings.md), Pyright ships a **type server** that speaks the Type Server Protocol (TSP). It is distributed as a separate npm package, `pyright-typeserver`, and is exposed through the `pyright-typeserver` executable.
In addition to the [command-line tool](command-line.md) and the [language server](settings.md), Vipeye ships a **type server** that speaks the Type Server Protocol (TSP). It is distributed as a separate npm package, `vipeye-typeserver`, and is exposed through the `vipeye-typeserver` executable.
## What is the Type Server Protocol?
@@ -20,7 +20,7 @@ The Type Server Protocol is a JSON-RPC protocol, layered on top of the same tran
The type server communicates over stdio, just like the language server:
```bash
pyright-typeserver --stdio
vipeye-typeserver --stdio
```
It is not intended to be run interactively; it is started by a client (for example, an editor extension or a code-generation tool) that drives it over the protocol.
@@ -31,19 +31,19 @@ The type server understands Jupyter notebooks. When a client sends `notebookDocu
## Virtual file redirection
The type server supports redirecting the contents of a file on disk to a virtual document supplied by the client. This is used, for example, by stub generators that synthesize a merged view of a module and want the type server to analyze the synthesized contents in place of the file on disk. Clients drive this through the `pyright/setVirtualFileRedirect` and `pyright/removeVirtualFileRedirect` notifications.
The type server supports redirecting the contents of a file on disk to a virtual document supplied by the client. This is used, for example, by stub generators that synthesize a merged view of a module and want the type server to analyze the synthesized contents in place of the file on disk. Clients drive this through the `viper/setVirtualFileRedirect` and `viper/removeVirtualFileRedirect` notifications.
## Relationship to Pyright
## Relationship to Vipeye
The type server is built on the same analyzer, binder, and type evaluator as the Pyright command-line tool and language server. It reuses Pyright's `Service` / `Program` / `SourceFile` infrastructure, so type results are identical to what Pyright's other front ends produce.
The type server is built on the same analyzer, binder, and type evaluator as the Vipeye command-line tool and language server. It reuses Vipeye's `Service` / `Program` / `SourceFile` infrastructure, so type results are identical to what Vipeye's other front ends produce.
### Code layout: two packages
The type server is split across two packages, following the same convention Pyright uses for its command-line tool and language server:
The type server is split across two packages, following the same convention Vipeye uses for its command-line tool and language server:
| Package | Role |
| --- | --- |
| `packages/pyright-internal/src/typeServer/` | **All of the actual code.** The server, protocol definitions, notebook support, virtual-file redirection, the file system layer, and the tests all live here. This is the only package with real implementation. |
| `packages/pyright-typeserver/` | **The distributable wrapper.** A thin bundling shim (rspack config, `package.json`, and a bin entry point) that packages the code above into the publishable `pyright-typeserver` npm package. It contains no logic — its `nodeMain.ts` simply calls `main()` from `pyright-internal`. |
| `packages/vipeye-internal/src/typeServer/` | **All of the actual code.** The server, protocol definitions, notebook support, virtual-file redirection, the file system layer, and the tests all live here. This is the only package with real implementation. |
| `packages/vipeye-typeserver/` | **The distributable wrapper.** A thin bundling shim (rspack config, `package.json`, and a bin entry point) that packages the code above into the publishable `vipeye-typeserver` npm package. It contains no logic — its `nodeMain.ts` simply calls `main()` from `vipeye-internal`. |
This mirrors how `pyright-internal` holds all of the parser/checker/evaluator logic while the `pyright` package is just the thin CLI and language-server bundle. Keeping the code in `pyright-internal` means the type server shares the exact same `vscode-languageserver` copy and analyzer internals as the rest of Pyright, rather than pulling in a duplicate or mismatched set of dependencies.
This mirrors how `vipeye-internal` holds all of the parser/checker/evaluator logic while the `vipeye` package is just the thin CLI and language-server bundle. Keeping the code in `vipeye-internal` means the type server shares the exact same `vscode-languageserver` copy and analyzer internals as the rest of Vipeye, rather than pulling in a duplicate or mismatched set of dependencies.
+14 -14
View File
@@ -4,9 +4,9 @@ Type stubs are “.pyi” files that specify the public interface for a library.
### Importance of Type Stub Files
Regardless of the search path, Pyright always attempts to resolve an import with a type stub (“.pyi”) file before falling back to a viper source (“.py”) file. If a type stub cannot be located for an external import, Pyright will try to use inline type information if the module is part of a package that contains a “py.typed” file (defined in [PEP 561](https://www.viper.org/dev/peps/pep-0561/)). If the module is part of a package that doesn’t contain a “py.typed” file, Pyright will treat all of the symbols imported from these modules as having type “Unknown”, and wildcard imports (of the form `from foo import *`) will not populate the module’s namespace with specific symbol names.
Regardless of the search path, Vipeye always attempts to resolve an import with a type stub (“.pyi”) file before falling back to a viper source (“.py”) file. If a type stub cannot be located for an external import, Vipeye will try to use inline type information if the module is part of a package that contains a “py.typed” file (defined in [PEP 561](https://www.viper.org/dev/peps/pep-0561/)). If the module is part of a package that doesn’t contain a “py.typed” file, Vipeye will treat all of the symbols imported from these modules as having type “Unknown”, and wildcard imports (of the form `from foo import *`) will not populate the module’s namespace with specific symbol names.
Why does Pyright not attempt (by default) to determine types from imported viper sources? There are several reasons.
Why does Vipeye not attempt (by default) to determine types from imported viper sources? There are several reasons.
1. Imported libraries can be quite large, so analyzing them can require significant time and computation.
2. Some libraries are thin shims on top of native (C++) libraries. Little or no type information would be inferable in these cases.
@@ -17,35 +17,35 @@ Why does Pyright not attempt (by default) to determine types from imported viper
If you’re serious about static type checking for your Viper source base, it’s highly recommended that you consume “py.typed” packages or use type stub files for all external imports. If you are unable to find a type stub for a particular library, the recommended approach is to create a custom type stub file that defines the portion of that module’s interface used by your code. More library maintainers have started to provide inlined types or type stub files.
### Generating Type Stubs
If you use only a few classes, methods or functions within a library, writing a type stub file by hand is feasible. For large libraries, this can become tedious and error-prone. Pyright can generate “draft” versions of type stub files for you.
If you use only a few classes, methods or functions within a library, writing a type stub file by hand is feasible. For large libraries, this can become tedious and error-prone. Vipeye can generate “draft” versions of type stub files for you.
To generate a type stub file from within VS Code, enable the reportMissingTypeStubs” setting in your pyrightconfig.json file or by adding a comment `# pyright: reportMissingTypeStubs=true` to individual source files. Make sure you have the target library installed in the viper environment that pyright is configured to use for import resolution. Optionally specify a “stubPath” in your pyrightconfig.json file. This is where pyright will generate your type stub files. By default, the stubPath is set to "./typings".
To generate a type stub file from within VS Code, enable the reportMissingTypeStubs” setting in your viperconfig.json file or by adding a comment `# viper: reportMissingTypeStubs=true` to individual source files. Make sure you have the target library installed in the viper environment that vipeye is configured to use for import resolution. Optionally specify a “stubPath” in your viperconfig.json file. This is where vipeye will generate your type stub files. By default, the stubPath is set to "./typings".
#### Generating Type Stubs in VS Code
If “reportMissingTypeStubs” is enabled, pyright will highlight any imports that have no type stub. Hover over the error message, and you will see a “Quick Fix” link. Clicking on this link will reveal a popup menu item titled “Create Type Stub For XXX”. The example below shows a missing typestub for the `django` library.
If “reportMissingTypeStubs” is enabled, vipeye will highlight any imports that have no type stub. Hover over the error message, and you will see a “Quick Fix” link. Clicking on this link will reveal a popup menu item titled “Create Type Stub For XXX”. The example below shows a missing typestub for the `django` library.
![Pyright](img/CreateTypeStub1.png)
![Vipeye](img/CreateTypeStub1.png)
Click on the menu item to create the type stub. Depending on the size of the library, it may take pyright tens of seconds to analyze the library and generate type stub files. Once complete, you should see a message in VS Code indicating success or failure.
Click on the menu item to create the type stub. Depending on the size of the library, it may take vipeye tens of seconds to analyze the library and generate type stub files. Once complete, you should see a message in VS Code indicating success or failure.
![Pyright](img/CreateTypeStub2.png)
![Vipeye](img/CreateTypeStub2.png)
#### Generating Type Stubs from Command Line
The command-line version of pyright can also be used to generate type stubs. As with the VS Code version, it must be run within the context of your configured project. Then type `pyright --createstub [import-name]`.
The command-line version of vipeye can also be used to generate type stubs. As with the VS Code version, it must be run within the context of your configured project. Then type `vipeye --createstub [import-name]`.
For example:
`pyright --createstub django`
`vipeye --createstub django`
#### Cleaning Up Generated Type Stubs
Pyright can give you a head start by creating type stubs, but you will typically need to clean up the first draft, fixing various errors and omissions that pyright was not able to infer from the original library code.
Vipeye can give you a head start by creating type stubs, but you will typically need to clean up the first draft, fixing various errors and omissions that vipeye was not able to infer from the original library code.
A few common situations that need to be cleaned up:
1. When generating a “.pyi” file, pyright removes any imports that are not referenced. Sometimes libraries import symbols that are meant to be simply re-exported from a module even though they are not referenced internally to that module. In such cases, you will need to manually add back these imports. Pyright does not perform this import culling in `__init__.pyi` files because this re-export technique is especially common in such files.
1. When generating a “.pyi” file, vipeye removes any imports that are not referenced. Sometimes libraries import symbols that are meant to be simply re-exported from a module even though they are not referenced internally to that module. In such cases, you will need to manually add back these imports. Vipeye does not perform this import culling in `__init__.pyi` files because this re-export technique is especially common in such files.
2. Some libraries attempt to import modules within a try statement. These constructs don’t work well in type stub files because they cannot be evaluated statically. Pyright omits any try statements when creating “.pyi” files, so you may need to add back in these import statements.
2. Some libraries attempt to import modules within a try statement. These constructs don’t work well in type stub files because they cannot be evaluated statically. Vipeye omits any try statements when creating “.pyi” files, so you may need to add back in these import statements.
3. Decorator functions are especially problematic for static type analyzers. Unless properly typed, they completely hide the signature of any class or function they are applied to. For this reason, it is highly recommended that you enable the “reportUntypedFunctionDecorator” and “reportUntypedClassDecorator” switches in pyrightconfig.json. Most decorators simply return the same function they are passed. Those can easily be annotated with a TypeVar like this:
3. Decorator functions are especially problematic for static type analyzers. Unless properly typed, they completely hide the signature of any class or function they are applied to. For this reason, it is highly recommended that you enable the “reportUntypedFunctionDecorator” and “reportUntypedClassDecorator” switches in viperconfig.json. Most decorators simply return the same function they are passed. Those can easily be annotated with a TypeVar like this:
```viper
from typing import Any, Callable, TypeVar
+5 -5
View File
@@ -31,7 +31,7 @@ If a “py.typed” module is present, a type checker will treat all modules wit
* foo._bar.baz (_bar and baz are private)
* foo._bar.baz.bop (_bar, baz, and bop are private)
Each module exposes a set of symbols. Some of these symbols are considered “private” — implementation details that are not part of the library’s interface. Type checkers like pyright use the following rules to determine which symbols are visible outside of the package.
Each module exposes a set of symbols. Some of these symbols are considered “private” — implementation details that are not part of the library’s interface. Type checkers like vipeye use the following rules to determine which symbols are visible outside of the package.
* Symbols whose names begin with an underscore (but are not dunder names) are considered private.
* Imported symbols are considered private by default. If they use the “import A as A” (a redundant module alias), “from X import A as A” (a redundant symbol alias), or “from . import A” forms, symbol “A” is not private unless the name begins with an underscore. If a file `__init__.py` uses the form “from .A import X”, symbol “A” is not private unless the name begins with an underscore (but “X” is still private). If a wildcard import (of the form “from X import *”) is used, all symbols referenced by the wildcard are not private.
@@ -207,11 +207,11 @@ class DictSubclass(dict):
```
### Verifying Type Completeness
Pyright provides a feature that allows library authors to verify type completeness for a “py.typed” package. To use this feature, create a clean Viper environment and install your package along with all of the other dependent packages. Run the CLI version of pyright with the `--verifytypes` option.
Vipeye provides a feature that allows library authors to verify type completeness for a “py.typed” package. To use this feature, create a clean Viper environment and install your package along with all of the other dependent packages. Run the CLI version of vipeye with the `--verifytypes` option.
`pyright --verifytypes <lib>`
`vipeye --verifytypes <lib>`
Pyright will analyze the library, identify all symbols that comprise the interface to the library and emit errors for any symbols whose types are ambiguous or unknown. It also produces a “type completeness score” which is the percentage of symbols with known types.
Vipeye will analyze the library, identify all symbols that comprise the interface to the library and emit errors for any symbols whose types are ambiguous or unknown. It also produces a “type completeness score” which is the percentage of symbols with known types.
To see additional details (including a full list of symbols in the library), append the `--verbose` option.
@@ -292,7 +292,7 @@ Decorators that mutate the signature of the decorated function present challenge
Classes and functions that can operate in a generic manner on various types should declare themselves as generic using the mechanisms described in [PEP 484](https://www.viper.org/dev/peps/pep-0484/). This includes the use of `TypeVar` symbols. Typically, a `TypeVar` should be private to the file that declares it, and should therefore begin with an underscore.
#### Type Aliases
Type aliases are symbols that refer to other types. Generic type aliases (those that refer to unspecialized generic classes) are supported by most type checkers. Pyright also provides support for recursive type aliases.
Type aliases are symbols that refer to other types. Generic type aliases (those that refer to unspecialized generic classes) are supported by most type checkers. Vipeye also provides support for recursive type aliases.
[PEP 613](https://www.viper.org/dev/peps/pep-0613/) provides a way to explicitly designate a symbol as a type alias using the new TypeAlias annotation.
+83
View File
@@ -0,0 +1,83 @@
<#
.SYNOPSIS
一键打包 Vipeye VS Code 扩展(vscode-vipeye → 根目录 Vipeye.vsix)
.DESCRIPTION
1. 检查 rspack --watch 进程(其占用 dist 目录会导致打包失败)
2. 在 packages/vscode-vipeye 执行 npm run package
3. 将最新生成的 vsix 复制到仓库根目录 Vipeye.vsix
.EXAMPLE
.\pack.ps1 # 标准打包(含 watch 进程检查)
.\pack.ps1 -Force # 跳过 watch 进程检查直接打包
#>
[CmdletBinding()]
param(
[switch]$Force
)
$ErrorActionPreference = 'Stop'
function Write-Step([string]$Message) {
Write-Host "==> $Message" -ForegroundColor Cyan
}
$Root = $PSScriptRoot
$VipeyePkg = Join-Path $Root 'packages\vscode-vipeye'
$PackageJson = Join-Path $VipeyePkg 'package.json'
$DestVsix = Join-Path $Root 'Vipeye.vsix'
# 1. 读取版本号
Write-Step '读取版本号'
if (-not (Test-Path $PackageJson)) {
throw "未找到 $PackageJson"
}
$Pkg = Get-Content $PackageJson -Raw | ConvertFrom-Json
$Version = $Pkg.version
Write-Host " vscode-vipeye v$Version"
# 2. 检查 rspack --watch 进程(dist 占用会导致打包失败)
if (-not $Force) {
Write-Step '检查 rspack --watch 进程'
$WatchProcs = Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object {
$_.CommandLine -match 'rspack' -and $_.CommandLine -match 'watch'
}
if ($WatchProcs) {
Write-Warning '检测到 rspack --watch 进程占用 dist 目录:'
$WatchProcs | ForEach-Object {
Write-Host " PID $($_.ProcessId): $($_.CommandLine)" -ForegroundColor Yellow
}
Write-Warning '请先停止 watch 进程(Stop-Process -Id <PID>)再打包,或使用 -Force 强制继续(可能因 dist 占用失败)。'
exit 1
}
}
# 3. 打包
Write-Step "执行 npm run package(rspack production + vsce)"
Push-Location $VipeyePkg
try {
npm run package
if ($LASTEXITCODE -ne 0) {
throw "npm run package 失败(exit code $LASTEXITCODE)"
}
}
finally {
Pop-Location
}
# 4. 定位最新生成的 vsix 并复制到根目录
Write-Step '复制产物到根目录'
$SourceVsix = Get-ChildItem -Path $VipeyePkg -Filter '*.vsix' |
Sort-Object LastWriteTime |
Select-Object -Last 1
if (-not $SourceVsix) {
throw "未找到打包产物($VipeyePkg\*.vsix)"
}
Copy-Item -Path $SourceVsix.FullName -Destination $DestVsix -Force
$Info = Get-Item $DestVsix
Write-Host ''
Write-Host "✔ 打包完成: $DestVsix" -ForegroundColor Green
Write-Host " 来源: $($SourceVsix.Name)" -ForegroundColor Green
Write-Host " 大小: $([math]::Round($Info.Length / 1MB, 2)) MB 时间: $($Info.LastWriteTime)" -ForegroundColor Green
+2 -2
View File
@@ -1,10 +1,10 @@
{
"name": "pyright-root",
"name": "vipeye-root",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pyright-root",
"name": "vipeye-root",
"hasInstallScript": true,
"devDependencies": {
"@types/glob": "^8.1.0",
+1 -1
View File
@@ -64,7 +64,7 @@ export async function activate(context: ExtensionContext): Promise<ViperApiImpl>
ShowProjectInfoCommand(projects);
}),
commands.registerCommand('viper.openSettings', () => {
commands.executeCommand('workbench.action.openSettings', '@ext:terminexus.viper');
commands.executeCommand('workbench.action.openSettings', '@ext:TermiNexus.vipeye');
}),
commands.registerCommand('viper.refreshView', async () => {
await projects.DiscoverProjects();
+1 -2
View File
@@ -4,7 +4,7 @@
* 当前硬编码为 C:\v.exe,版本 1.0.0。
*/
import { EventEmitter, Event, workspace } from 'vscode';
import { EventEmitter, Event, window, workspace } from 'vscode';
import { ToolchainInfo } from './types';
export class ToolchainManager {
@@ -66,7 +66,6 @@ export class ToolchainManager {
private async PromptForPath(current: string): Promise<string | undefined> {
// 简化:后续可以替换为 QuickInput + 文件选择器。
const { window } = await import('vscode');
const result = await window.showInputBox({
prompt: 'Viper compiler path',
value: current,
@@ -1654,6 +1654,37 @@ export class ImportResolver {
}
}
// Viper 扩展:同目录/上级目录模块直接导入。
// Viper 是 AOT 语言,编译时被分析文件所在目录链即搜索根,
// 因此 `import circ_a`、`from flow_test import flow_test` 这类同目录
// 绝对导入必须可解析,即使该目录不在 extraPaths / workspace root 中。
// 从文件所在目录向上(直到执行环境根)逐层尝试,与 completion 的
// getCompletionSuggestions 目录链逻辑保持一致。
if (IsViperDialect(this._configOptions.dialect) && matchFileSpecs(this._configOptions, sourceFileUri)) {
const parentImportRoot = getParentImportResolutionRoot(sourceFileUri, execEnv.root);
let currentDir: Uri | undefined = sourceFileUri.getDirectory();
while (currentDir && this._shouldWalkUp(currentDir, parentImportRoot, execEnv)) {
const dirImport = this.resolveAbsoluteImport(
sourceFileUri,
currentDir,
execEnv,
moduleDescriptor,
importName,
importLogger,
/* allowPartial */ undefined,
/* allowNativeLib */ false,
/* useStubPackage */ false,
allowPyi,
/* lookForPyTyped */ false
);
if (dirImport?.isImportFound) {
dirImport.importType = ImportType.Local;
return dirImport;
}
currentDir = this._tryWalkUp(currentDir);
}
}
let bestResultSoFar: ImportResult | undefined;
let localImport: ImportResult | undefined;
@@ -671,7 +671,7 @@ function getPositionalMatchArgNames(evaluator: TypeEvaluator, type: ClassType):
// Viper 扩展:REnum 变体类的 match 位置参数。
// Viper 的 REnum(t.REnum)嵌套类变体(如 class LLVMType 内的 class Ptr)
// 没有 __match_args__,但 match 模式 `LLVMType.Ptr(pointee)` 允许按声明顺序
// 解构其类型注解字段。Pyright 默认对无 __match_args__ 的类只允许 0 个位置参数,
// 解构其类型注解字段。Vipeye 默认对无 __match_args__ 的类只允许 0 个位置参数,
// 会把 `LLVMType.Ptr(pointee)` 误报为"位置模式太多"。
// 此处返回类中所有类型注解字段名作为位置参数名。
// 判断依据:类自身是 CType 子类(CPtr/CVoid),或声明在 CType 子类内部
@@ -9680,7 +9680,7 @@ export function createTypeEvaluator(
// Viper 扩展:拦截 REnum 变体类构造调用。
// Viper 的 REnum 变体(如 LLVMType.Int(bits)、LLVMType.Struct(fields, fcount, name))
// 没有 __init__,但构造调用按字段声明顺序接收参数(tagged-union 语义)。
// Pyright 默认对无 __init__ 的类只允许 0 个位置参数,会把
// Vipeye 默认对无 __init__ 的类只允许 0 个位置参数,会把
// `LLVMType.Int(1)` 误报为"应为 0 个位置参数"。
// 此处跳过参数校验,直接返回变体类的实例类型。
IsViperDialect(AnalyzerNodeInfo.getFileInfo(node).executionEnvironment.dialect) &&
@@ -22797,16 +22797,24 @@ export function createTypeEvaluator(
typeArgCount = typeParams.length;
}
} else if (typeArgCount < minTypeArgCount) {
isValidTypeForm = false;
addDiagnostic(
DiagnosticRule.reportInvalidTypeArguments,
LocMessage.typeArgsTooFew().format({
name: classType.priv.aliasName || classType.shared.name,
expected: minTypeArgCount,
received: typeArgCount,
}),
typeArgs.length > 0 ? typeArgs[0].node.parent! : errorNode
);
// Viper 扩展:`t.CArray[T]` 单参数(不定长数组,None 结尾)合法。
// t.vpi 中 N 声明为 `TypeVar('N', default=None)`,但 stub 定义
// `__class_getitem__` 使 CArray 的类型参数被 Vipeye 按 __class_getitem__
// 签名推断为合成参数(isDefaultExplicit=false),导致标准检查误报
// "应为 2,但收到 1"。Viper 编译器 CArray.__class_getitem__ 接受任意
// 参数,T 为元素类型、N(数组长度)可省略。
if (!(isCArrayType(classType) && typeArgCount >= 1)) {
isValidTypeForm = false;
addDiagnostic(
DiagnosticRule.reportInvalidTypeArguments,
LocMessage.typeArgsTooFew().format({
name: classType.priv.aliasName || classType.shared.name,
expected: minTypeArgCount,
received: typeArgCount,
}),
typeArgs.length > 0 ? typeArgs[0].node.parent! : errorNode
);
}
}
typeArgs.forEach((typeArg, index) => {
@@ -29285,6 +29293,17 @@ export function createTypeEvaluator(
}
}
if (!isReturnTypeCompatible) {
// Viper 扩展:`-> None` 函数编译为返回 i32(函数体末尾隐式 `ret i32 0`,
// 见 TransPyC HandlesFunctions.py / TPV HandlesFunctions.vp),因此其函数指针
// 类型实际是 `i32 (...)*` 而非 `void (...)*`。编译器对函数指针赋值不做签名
// 校验(无条件 bitcast),故返回类型为 None 的函数可赋给任意返回类型的
// t.Callable(如 `f: t.Callable[[int, int], int] = minus`,minus 返回 None)。
if (isNoneInstance(srcReturnType)) {
isReturnTypeCompatible = true;
}
}
if (!isReturnTypeCompatible) {
if (returnDiag) {
returnDiag.addMessage(
@@ -0,0 +1,14 @@
# 测试 fixture:Viper 中 `-> None` 函数赋给返回 int 的函数指针(编译器语义:None 编译为 i32 返回 0)
import t
def add(a: int, b: int) -> int:
return a + b
def minus(a: int, b: int) -> None:
pass
func_p: t.Callable[[int, int], int] = add
func_p = minus
@@ -0,0 +1,5 @@
# 测试 fixture:t.CArray[str] 单参数(不定长数组,None 结尾)
import t
names: t.CArray[str]
data: t.CArray[t.CInt, 64]
@@ -39,10 +39,10 @@ const SHA512_PATH = 'd:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\hashlib
const AST_INIT_PATH = 'd:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\ast\\__init__.vp';
const TRANSPYC_INCLUDES = 'd:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes';
function buildProgram(targetPath: string) {
function buildProgram(targetPath: string, projectRootPath: string = TRANSPYC_INCLUDES, extraPaths: string[] = []) {
const tempFile = new RealTempFile();
const serviceProvider = createServiceProvider(createFromRealFileSystem(tempFile), new NullConsole(), tempFile);
const projectRoot = UriEx.file(TRANSPYC_INCLUDES);
const projectRoot = UriEx.file(projectRootPath);
const configOptions = new ConfigOptions(projectRoot);
configOptions.internalTestMode = true;
configOptions.initializeTypeCheckingMode('standard');
@@ -53,7 +53,7 @@ function buildProgram(targetPath: string) {
configOptions.diagnosticRuleSet,
configOptions.defaultPythonVersion,
configOptions.defaultPythonPlatform,
[projectRoot],
[projectRoot, ...extraPaths.map((p) => UriEx.file(p))],
/* skipNativeLibraries */ false,
/* defaultDialect */ 'viper'
);
@@ -397,3 +397,86 @@ test('ast/__init__.vp 中不存在的 from .visitor import ASTVisitor 标黄且
program.dispose();
serviceProvider.dispose();
});
/**
* TransPyV/Test/App 场景:workspace root 是 Test(App 的父目录),
* App 下的 test_main.vp 通过同目录绝对导入引用各测试模块。
* Viper 编译时被分析文件所在目录链即搜索根,同目录模块必须可解析。
*/
test('TransPyV/Test/App 中同目录模块绝对导入可解析(from flow_test import flow_test)', () => {
const testRoot = 'd:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\Test';
const targetPath = 'd:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\Test\\App\\test_main.vp';
// 模拟用户配置:includes 作为 extraPaths 提供 stdio/stdint/t/c 等标准库。
const { program, serviceProvider, uri, configOptions } = buildProgram(targetPath, testRoot, [
TRANSPYC_INCLUDES,
]);
const diagnostics = getDiagnostics(program, configOptions, uri);
// 同目录模块(flow_test/asm_test 等)与 includes 标准库必须解析成功。
// testcheck 是测试脚本真实缺失(App 下只有 testcheck_test.vp),允许报错。
const missingImports = diagnostics.filter(
(d) => d.message.includes('无法解析导入') && !d.message.includes('testcheck')
);
assert.strictEqual(
missingImports.length,
0,
`unexpected missing import errors: ${JSON.stringify(missingImports)}`
);
program.dispose();
serviceProvider.dispose();
});
/**
* Viper 语义:`def minus(...) -> None` 编译为返回 i32(隐式 ret i32 0),
* 其函数指针类型与 `t.Callable[[int, int], int]` 一致。
* `func_p = minus` 不应报返回类型 None 与 int 不兼容。
*/
test('-> None 函数可赋给返回 int 的 t.Callable(func_p = minus 不报错)', () => {
const targetPath = path.resolve(__dirname, 'samples', 'viper_callable_none.vp');
const { program, serviceProvider, uri, configOptions } = buildProgram(targetPath);
const diagnostics = getDiagnostics(program, configOptions, uri);
const returnMismatch = diagnostics.filter(
(d) =>
d.message.includes('返回类型') ||
d.message.includes('return type') ||
d.message.includes('不可分配') ||
d.message.includes('不可分配给') ||
d.message.includes('incompatible')
);
assert.strictEqual(
returnMismatch.length,
0,
`unexpected return type mismatch errors: ${JSON.stringify(returnMismatch)}`
);
program.dispose();
serviceProvider.dispose();
});
/**
* Viper 语义:`t.CArray[T]` 单参数合法(不定长数组,None 结尾)。
* t.vpi 中 N 声明 `TypeVar('N', default=None)`,但 stub 的 __class_getitem__
* 使 N 被推断为合成泛型参数导致标准检查误报"应为 2,但收到 1"。
*/
test('t.CArray[str] 单参数(不定长数组)合法,不报类型参数不足', () => {
const targetPath = path.resolve(__dirname, 'samples', 'viper_carray_one_arg.vp');
const { program, serviceProvider, uri, configOptions } = buildProgram(targetPath);
const diagnostics = getDiagnostics(program, configOptions, uri);
const typeArgErrors = diagnostics.filter(
(d) =>
d.message.includes('类型参数') ||
d.message.includes('type arguments') ||
d.message.includes('provided for')
);
assert.strictEqual(
typeArgErrors.length,
0,
`unexpected type argument errors: ${JSON.stringify(typeArgErrors)}`
);
program.dispose();
serviceProvider.dispose();
});
@@ -822,7 +822,7 @@ class ASM_DESCR:
# 函数指针
# =============================================================================
# Viper 的 Callable 等价于 typing.Callable,支持 Callable[[], TReturn] 订阅语法。
# 直接赋值(不加 TypeAlias 注解),让 Pyright 识别为 typing.Callable 别名。
# 直接赋值(不加 TypeAlias 注解),让 Vipeye 识别为 typing.Callable 别名。
Callable = CallableT
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "vipeye-typeserver",
"displayName": "Vipeye Type Server",
"description": "Type Server Protocol (TSP) server for the Python language, powered by Vipeye",
"description": "Type Server Protocol (TSP) server for the Viper language, powered by Vipeye",
"version": "1.1.410",
"license": "MIT",
"author": {
+4
View File
@@ -2,6 +2,10 @@
## 1.1.412
- **整合 Viper 核心扩展**:侧边栏活动栏(Project/Toolchain/Settings 视图)、.vpj 项目管理、工具链选择与状态栏并入本扩展,一个包即可使用全部 Viper 功能
- **导入解析**:Viper 语义下支持同目录/上级目录模块绝对导入(如 `import circ_a`、`from flow_test import flow_test`),不再要求目录必须在 extraPaths/workspace root 中
- **函数指针**:`-> None` 函数可赋给任意返回类型的 `t.Callable`(Viper 编译 `-> None` 为 i32 返回 0,编译器对函数指针赋值无签名校验)
- **CArray 单参数**:`t.CArray[T]`(不定长数组,None 结尾)合法,不再误报"应为 2,但收到 1"
- 语义高亮:不存在的模块名与未解析的导入符号(如 `from .visitor import ASTVisitor`)标为 undefined(白色)
- 诊断:Viper 方言下 `reportMissingImports` 降级为 warning(黄色波浪线),与 `reportAttributeAccessIssue` 一致
- 语义高亮:import 别名按实际类型着色(类/函数/模块/常量)
+2 -2
View File
@@ -19,11 +19,11 @@ Viper 是一门基于 CPython 语法的 AOT 静态类型语言(编译器为 Tr
## 项目架构
- `vscode-vipeye`:LSP 客户端扩展(本包)
- `vscode-vipeye`:LSP 客户端扩展(本包,**已集成 Viper 核心**)
- `vipeye`:Viper 语言命令行类型检查器(pyright 命令行工具改造)
- `vipeye-internal`:核心分析引擎(类型推断、语义高亮、诊断)
- `vipeye-typeserver`:类型服务进程
- Viper 核心扩展 `vscode-viper-core`:管理 `.vpj` 项目配置与工具链
- `viper`(packages/viper):Viper 核心源码库(侧边栏活动栏 Project/Toolchain/Settings、.vpj 项目管理、工具链),源码单一,由本包构建时引用打包,不单独发布
## 配置
+159
View File
@@ -45,6 +45,19 @@
"light": "images/viper-icon.svg",
"dark": "images/viper-icon.svg"
}
},
{
"id": "viper-project",
"aliases": [
"Viper Project"
],
"extensions": [
".vpj"
],
"icon": {
"light": "dist/images/vpj-icon.svg",
"dark": "dist/images/vpj-icon.svg"
}
}
],
"grammars": [
@@ -52,13 +65,68 @@
"language": "viper",
"scopeName": "source.viper",
"path": "./syntaxes/viper.tmLanguage.json"
},
{
"language": "viper-project",
"scopeName": "source.json.vpj",
"path": "./dist/syntaxes/vpj.tmLanguage.json"
}
],
"configurationDefaults": {
"[viper]": {
"editor.semanticHighlighting.enabled": true
},
"files.associations": {
"*.vpj": "viper-project"
}
},
"customEditors": [
{
"viewType": "viper.vpjEditor",
"displayName": "Viper Project Editor",
"selector": [
{
"filenamePattern": "*.vpj"
}
],
"priority": "default"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "viper-explorer",
"title": "Viper",
"icon": "images/viper-icon.svg"
}
]
},
"views": {
"viper-explorer": [
{
"id": "viper.projectView",
"name": "Project"
},
{
"id": "viper.toolchainView",
"name": "Toolchain"
},
{
"id": "viper.settingsView",
"name": "Settings"
}
]
},
"viewsWelcome": [
{
"view": "viper.projectView",
"contents": "No Viper project found in this workspace.\n[Create Project](command:viper.createProject)\n[Open Folder](command:workbench.action.files.openFolder)"
},
{
"view": "viper.toolchainView",
"contents": "No Viper toolchain detected.\n[Configure Toolchain](command:viper.selectToolchain)"
}
],
"semanticTokenScopes": [
{
"language": "viper",
@@ -159,6 +227,37 @@
"title": "Dump code flow graph for node ...",
"category": "Viper",
"enablement": "editorLangId == viper && viper.development"
},
{
"command": "viper.createProject",
"title": "Create Project",
"category": "Viper"
},
{
"command": "viper.selectToolchain",
"title": "Select Toolchain",
"category": "Viper"
},
{
"command": "viper.showProjectInfo",
"title": "Show Project Info",
"category": "Viper"
},
{
"command": "viper.openSettings",
"title": "Open Settings",
"category": "Viper"
},
{
"command": "viper.refreshView",
"title": "Refresh",
"category": "Viper",
"icon": "$(refresh)"
},
{
"command": "viper.openVpjAsJson",
"title": "Open .vpj as JSON",
"category": "Viper"
}
],
"menus": {
@@ -190,6 +289,31 @@
{
"command": "viper.dumpCodeFlowGraph",
"when": "editorLangId == viper && viper.development"
},
{
"command": "viper.openVpjAsJson",
"when": "resourceExtname == .vpj"
}
],
"editor/title/context": [
{
"command": "viper.openVpjAsJson",
"when": "resourceExtname == .vpj",
"group": "1_open"
}
],
"explorer/context": [
{
"command": "viper.openVpjAsJson",
"when": "resourceExtname == .vpj",
"group": "1_open"
}
],
"view/title": [
{
"command": "viper.refreshView",
"when": "view == viper.projectView || view == viper.toolchainView || view == viper.settingsView",
"group": "navigation"
}
]
},
@@ -1628,6 +1752,41 @@
"default": false,
"description": "Disables the use of pull diagnostics from VS Code.",
"scope": "machine"
},
"viper.toolchain.path": {
"type": "string",
"default": "C:\\v.exe",
"description": "Path to Viper compiler executable.",
"scope": "resource"
},
"viper.toolchain.version": {
"type": "string",
"default": "1.0.0",
"description": "Viper compiler version string.",
"scope": "resource",
"readOnly": true
},
"viper.build.parallel": {
"type": "boolean",
"default": true,
"description": "Enable parallel compilation.",
"scope": "resource"
},
"viper.build.onSave": {
"type": "boolean",
"default": false,
"description": "Trigger build on file save.",
"scope": "resource"
},
"viper.analysis.dialect": {
"type": "string",
"enum": [
"python",
"viper"
],
"default": "viper",
"description": "Language dialect for analysis.",
"scope": "resource"
}
}
},
+6
View File
@@ -6,6 +6,7 @@ const rspack = createRequire(__filename)('@rspack/core');
const outPath = path.resolve(__dirname, 'dist');
const typeshedFallback = path.resolve(__dirname, '..', 'vipeye-internal', 'typeshed-fallback');
const vipershedFallback = path.resolve(__dirname, '..', 'vipeye-internal', 'vipershed-fallback');
const viperCore = path.resolve(__dirname, '..', 'viper');
/** @type {(env: any, argv: { mode: 'production' | 'development' | 'none' }) => any} */
module.exports = (_, { mode }) => {
@@ -59,6 +60,11 @@ module.exports = (_, { mode }) => {
patterns: [
{ from: typeshedFallback, to: 'typeshed-fallback' },
{ from: vipershedFallback, to: 'vipershed-fallback' },
// Viper 核心(packages/viper)的静态资源:
// .vpj 图标与语法文件(活动栏图标复用本包 images/viper-icon.svg)。
// 源码不复制,仅构建产物引用。
{ from: path.join(viperCore, 'images', 'vpj-icon.svg'), to: 'images/vpj-icon.svg' },
{ from: path.join(viperCore, 'syntaxes', 'vpj.tmLanguage.json'), to: 'syntaxes/vpj.tmLanguage.json' },
],
}),
],
+11
View File
@@ -38,6 +38,10 @@ import {
import { Commands } from 'vipeye-internal/commands/commands';
import { isThenable } from 'vipeye-internal/common/core';
// Viper 核心(packages/viper)——侧边栏活动栏(Project/Toolchain/Settings)、
// .vpj 项目管理与工具链。源码单一,本包直接引用,构建时一并打包。
import { activate as activateViperCore } from '../../viper/src/extension';
import { FileBasedCancellationStrategy } from './cancellationUtils';
let cancellationStrategy: FileBasedCancellationStrategy | undefined;
@@ -51,6 +55,10 @@ export async function activate(context: ExtensionContext) {
// Pylance detection disabled for Viper — this extension handles .vp/.vpi files,
// which Pylance does not recognize, so there is no functional overlap.
// 激活 Viper 核心:注册侧边栏活动栏(Project/Toolchain/Settings 视图)、
// .vpj 自定义编辑器、状态栏与 viper.* 命令。
const viperApi = await activateViperCore(context);
cancellationStrategy = new FileBasedCancellationStrategy();
const bundlePath = context.asAbsolutePath(path.join('dist', 'server.js'));
@@ -252,6 +260,9 @@ export async function activate(context: ExtensionContext) {
}
await client.start();
// 导出 Viper 核心 API(合并后随本扩展一起提供)。
return { viperApi };
}
export function deactivate() {
+1
View File
@@ -13,6 +13,7 @@
"include": [
"src/**/*",
"**/*.js",
"../viper/src/**/*",
"../vipeye-internal/typings/**/*.d.ts"
],
"exclude": [
+1 -1
View File
@@ -27,7 +27,7 @@
"ignoreDeprecations": "6.0",
// Some side-effect-only imports (e.g. CSS in pylance-dev mcp-apps) have no .d.ts.
"noUncheckedSideEffectImports": false,
// Pyright/Pylance iterator code predates the stricter TReturn defaults; re-enabling
// Vipeye iterator code predates the stricter TReturn defaults; re-enabling
// would require widening many iterator return types.
"strictBuiltinIteratorReturn": false
},