Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent behavior between pylance and pyright #9702

Open
xixixao opened this issue Jan 14, 2025 · 17 comments
Open

Inconsistent behavior between pylance and pyright #9702

xixixao opened this issue Jan 14, 2025 · 17 comments
Assignees
Labels
addressed in next version Issue is fixed and will appear in next published version bug Something isn't working

Comments

@xixixao
Copy link

xixixao commented Jan 14, 2025

Describe the bug
Pyright CLI is reporting a type error, Pylance does not (even reporting "unused type: ignore" if that rule is enabled).

Code

from upath import UPath

UPath("az://power-europe/processed", account_name="sfcommodgwcdataftr", anon=False)

This is from
universal-pathlib = "0.1.4"

Pyright reports

./test.py
  ./test.py:3:38 - error: No parameter named "account_name" (reportCallIssue)
  ./test.py:3:73 - error: No parameter named "anon" (reportCallIssue)
2 errors, 0 warnings, 0 informations

VS Code extension or command-line
Pylance: 2024.12.1
Pyright: 1.1.389

Repro

Assuming you have poetry and Python 3.11 installed:

git clone https://github.com/xixixao/example-pyright-issue-upath
cd example-pyright-issue-upath
poetry env use python3.11
poetry install
poetry shell
PYRIGHT_PYTHON_PYLANCE_VERSION="latest-release" pyright test.py
@xixixao xixixao added the bug Something isn't working label Jan 14, 2025
@erictraut
Copy link
Collaborator

Pylance is built on top of pyright, so if you use the same version and configure them the same, they will output the same results. For a list of possible reasons why you're seeing a difference, refer to this documentation.

If you can't figure it out from the documentation, feel free to respond back here, and I'll try to help you out further.

I'm going to close in the meantime because this isn't an actionable pyright bug.

@erictraut erictraut closed this as not planned Won't fix, can't repro, duplicate, stale Jan 14, 2025
@erictraut erictraut added the as designed Not a bug, working as intended label Jan 14, 2025
@xixixao
Copy link
Author

xixixao commented Jan 16, 2025

@erictraut

  1. I have confirmed the pyright version is the same
  2. I have checked the bundled stubs, and they do not seem to include the library in question. I have also followed the instructions and copied the stubs over and added them to config.
  3. I have added
[tool.pyright]
autoSearchPaths=false
extraPaths=[] # Include paths from PYTHONPATH env var and .env definition
typeCheckingMode="standard"
reportShadowedImports="warning"

to pyproject.toml.

I am still observing the divergent behavior.

I have updated the example repo with the stubs and the config, could you try it out?

@erictraut
Copy link
Collaborator

Both pyright and pylance report the same error for me with the code snippet above. I'm using the latest version of pylance (2024.12.1) and the latest version of pyright (1.1.392). I'm using the same virtual environment in both cases.

Are you seeing any typing-related errors from pylance? For example, does the following code produce an error?

x: int = ""

How about basic syntax errors?

1 +

@xixixao
Copy link
Author

xixixao commented Jan 17, 2025

Thanks for trying it out @erictraut !

A colleague of mine identified the root cause. It is because Pylance uses the version of python specified in given venv, while Pyright requires specifying the version:

[tool.pyright]
pythonVersion = "3.11"

I would suggest:

  1. At least add this gotcha to the FAQ page you linked (also having this linked somewhere more prominently from Pyright docs/repo would be nice)
  2. Fix this by also using the version of Python from the currently active venv

Meta point (but I think many have articulated this before): Having the typechecker run consistently between IDE and CI is a table stakes functionality. And this requires consistent CLI and IDE behavior. All efforts towards this goal will greatly benefit teams like ours.

Thanks for the great support!

@erictraut
Copy link
Collaborator

I'm glad you figured it out.

It is because Pylance uses the version of python specified in given venv, while Pyright requires specifying the version

That's not quite correct. Pyright and pylance both allow you to specify the Python version, but both will also auto-detect the version from the configured virtual environment. In the language server version of pyright (or in pylance, which is also a language server), you can configure the selected virtual environment in your editor. In the command-line version of pyright, you can simply activate the venv prior to running pyright. For more details, refer to this documentation.

@xixixao
Copy link
Author

xixixao commented Jan 18, 2025

@erictraut The behavior I'm observing does not match the docs:

  1. The docs do not mention pythonVersion, but it clearly affects which version of Python is used
  2. The docs say "As a fallback, use the default Python environment (i.e. the one that is invoked when typing python in the shell)." I can see that the venv is used, but the version of Python is not correct.

From the same shell,
pyright --verbose test.py:

Loading pyproject.toml file at /Users/foo/example-pyright-upath/pyproject.toml
Auto-excluding **/node_modules
Auto-excluding **/__pycache__
Auto-excluding **/.*
stubPath file:///Users/foo/example-pyright-upath/.stubs is not a valid directory.
Execution environment: python
  Extra paths:
    (none)
  Python version: 3.13
  Python platform: Darwin
  Search paths:
    /Users/foo/Library/Caches/pypoetry/virtualenvs/example-pyright-upath-qwEj-ALw-py3.11/lib/python3.11/site-packages/pyright/dist/dist/typeshed-fallback/stdlib
    /Users/foo/example-pyright-upath
    /Users/foo/example-pyright-upath/.stubs
    /Users/foo/Library/Caches/pypoetry/virtualenvs/example-pyright-upath-qwEj-ALw-py3.11/lib/python3.11/site-packages/pyright/dist/dist/typeshed-fallback/stubs/...
    /opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11
    /opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
    /Users/foo/Library/Caches/pypoetry/virtualenvs/example-pyright-upath-qwEj-ALw-py3.11/lib/python3.11/site-packages
Found 1 source file
pyright 1.1.392
/Users/foo/example-pyright-upath/test.py
  /Users/foo/example-pyright-upath/test.py:6:38 - error: No parameter named "account_name" (reportCallIssue)
  /Users/foo/example-pyright-upath/test.py:6:73 - error: No parameter named "anon" (reportCallIssue)
2 errors, 0 warnings, 0 informations
Completed in 0.389sec

python --version:

Python 3.11.11

But the linked documentation talks about environments, not Python versions, so it's not clear whether this is a bug in Pyright or the intended behavior.

@erictraut
Copy link
Collaborator

The pythonVersion setting doesn't affect which python environment is used for import resolution. However, it does allow you to override the version of python that you want pyright to assume when it performs its analysis. It is documented here. If you don't set pythonVersion, pyright will use the python version of your configured python environment. You therefore shouldn't need to set the pythonVersion manually unless you have a special use case — for example, if your python environment is a newer version but you want to ensure that your code is compatible with older versions of python.

You ran python --version above. Could you try running python3 --version? Does it give you the same result?

Can you provide your pyproject.toml settings? Based on the output you've shared above, it looks like you've set the pythonVersion to 3.13. If you don't provide a pythonVersion in your config file, pyright will detect that the configured environment is version 3.11. Pyright does this by simply "shell executing" python3 -c with a short script that outputs the version:

    import sys, json
    json.dump(tuple(sys.version_info), sys.stdout)

@xixixao
Copy link
Author

xixixao commented Jan 19, 2025

python3 --version outputs Python 3.11.11

The pyproject.toml is in the repo I provided:

[tool.poetry]
name = "example-pyright-upath"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
universal-pathlib = "0.1.4"
pyright = "^1.1.392.post0"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pyright]
autoSearchPaths=false
extraPaths=[] # Include paths from PYTHONPATH env var and .env definition
typeCheckingMode="standard"
reportShadowedImports="warning"
stubPath=".stubs"

The observed behavior was reproduced following the instructions I gave by other people in our company.

I have also tried:

node -e "require('child_process').exec('python3 -c \"import sys; print(sys.version_info)\"', (e, so, se) => { if (e) console.error(e); if (se) console.error(se); console.log(so); })"

getting:

sys.version_info(major=3, minor=11, micro=11, releaselevel='final', serial=0)

I have also tried using the brew version of pyright directly, instead of the pip wrapper:

/opt/homebrew/bin/pyright --verbose test.py

getting:

Loading pyproject.toml file at /Users/foo/example-pyright-upath/pyproject.toml
Auto-excluding **/node_modules
Auto-excluding **/__pycache__
Auto-excluding **/.*
stubPath file:///Users/foo/example-pyright-upath/.stubs is not a valid directory.
Execution environment: python
  Extra paths:
    (none)
  Python version: 3.13
  Python platform: Darwin
  Search paths:
    /opt/homebrew/Cellar/pyright/1.1.390/libexec/lib/node_modules/pyright/dist/typeshed-fallback/stdlib
    /Users/foo/example-pyright-upath
    /Users/foo/example-pyright-upath/.stubs
    /opt/homebrew/Cellar/pyright/1.1.390/libexec/lib/node_modules/pyright/dist/typeshed-fallback/stubs/...
    /opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11
    /opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
    /Users/foo/Library/Caches/pypoetry/virtualenvs/example-pyright-upath-qwEj-ALw-py3.11/lib/python3.11/site-packages
Found 1 source file
pyright 1.1.390
/Users/foo/example-pyright-upath/test.py
  /Users/foo/example-pyright-upath/test.py:6:38 - error: No parameter named "account_name" (reportCallIssue)
  /Users/foo/example-pyright-upath/test.py:6:73 - error: No parameter named "anon" (reportCallIssue)
2 errors, 0 warnings, 0 informations
Completed in 0.465sec

How is Pyright "shell executing"?

@erictraut
Copy link
Collaborator

Pyright has a function called getPythonVersion that calls the child_process.execFileSync node function here. The documentation for child_process.execFileSync can be found here.

@xixixao
Copy link
Author

xixixao commented Jan 19, 2025

@erictraut I added console.logs to the running Pyright JS. In my case the code doesn't invoke getPythonVersion, because it goes through this.getDefaultExecEnvironment() (this.executionEnvironments.length is 0), and because of this code:

if (configOptions.pythonPath) {
configOptions.ensureDefaultPythonVersion(host, this._console);
}

because configOptions.pythonPath is undefined.

Does this correspond to the docs As a fallback, use the default Python environment (i.e. the one that is invoked when typing python in the shell).?

Isn't this a bug? Or should my case not go through this.getDefaultExecEnvironment()?

@erictraut erictraut removed the as designed Not a bug, working as intended label Jan 20, 2025
@erictraut
Copy link
Collaborator

Thanks for investigating further. This does indeed look like a bug. Reopening.

@erictraut erictraut reopened this Jan 20, 2025
@erictraut
Copy link
Collaborator

@rchiodo, this looks like a regression that was introduced by a change you made several months ago. Do you happen to recall the context of this change? In particular, why is ensureDefaultPythonVersion called only when there is a pythonPath configured? I think it needs to be called unconditionally here to accommodate the case where there is no pythonPath configured. We should fall back on the python environment configured in the shell environment in that case.

        // Ensure default python version and platform. A default should only be picked if
        // there is a python path however.
        if (configOptions.pythonPath) {
            configOptions.ensureDefaultPythonVersion(host, this._console);
        }

@xixixao
Copy link
Author

xixixao commented Jan 21, 2025

Is it an accidental copy-paste? In the same file the ensureDefaultPythonVersion call was always guarded by if (configOptions.pythonPath).

@rchiodo
Copy link
Collaborator

rchiodo commented Jan 21, 2025

Sorry I don't recall. I put that comment there for a reason though. It wasn't there in the code that was copied.

@erictraut
Copy link
Collaborator

@rchiodo, is it OK if I assign you this issue? I think you have more context than I do.

@rchiodo
Copy link
Collaborator

rchiodo commented Jan 21, 2025

@rchiodo, is it OK if I assign you this issue? I think you have more context than I do.

Sure. I can reproduce the issue with 1.1.378, but not with 1.1.377. I'll see if I can figure out why I left that if statement there.

@rchiodo
Copy link
Collaborator

rchiodo commented Jan 21, 2025

The change was intended to fix this issue here:
#8797

If I'm recalling correctly that bug was because we were setting the default version before we actually had gotten the pythonPath so it was always defaulting to the python3 version.

I think moving the setting of the version after everything else should have been sufficient to fix that bug. I'll remove the if statement and make sure that original issue is still fixed.

@rchiodo rchiodo added the addressed in next version Issue is fixed and will appear in next published version label Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addressed in next version Issue is fixed and will appear in next published version bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants