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

The signature help information shown to users for class constructors in Pylance version v2024.8.1 is less useful that in Pylance version v2024.7.1. This also breaks parameter code completion for those methods. #6286

Closed
vcmlseg opened this issue Aug 22, 2024 · 8 comments
Assignees
Labels
by design langserver-diff Language server might want to differ from Pyright

Comments

@vcmlseg
Copy link

vcmlseg commented Aug 22, 2024

Type: Bug

Behaviour

Code completion for class constructors is broken in Pylance v2024.8.1 (was working in v2024.7.1), and the method signature pop-up displayed to the end user for a class constructor is unhelpful.

Pylance v2024.8.1:
2024 8 1 intellisense

Pylance v2024.7.1:
2024 7 1 intellisense

Steps to reproduce:

Given the following class: FxForwardCurveDefinition
Defined in: https://pypi.org/project/lseg-analytics/
Installed via: pip install lseg-analytics==1.0.0b2

Attempt to obtain code completion for the constructor of FxForwardCurveDefinition using Pylance v2024.8.1 and Pylance v2024.7 using the following snippet:

from lseg_analytics.market_data import fx_forward_curves

fx_forward_curves.FxForwardCurveDefinition(
 # attempt to trigger intellisense here
)

Diagnostic data

Output for Python in the Output panel - when Pylance v2024.8.1 is installed

2024-08-22 12:11:50.095 [info] Experiment 'pythonaa' is active
2024-08-22 12:11:50.095 [info] Experiment 'pythonRecommendTensorboardExt' is active
2024-08-22 12:11:50.095 [info] Experiment 'pythonREPLSmartSend' is active
2024-08-22 12:11:50.096 [info] Experiment 'pythonTerminalEnvVarActivation' is active
2024-08-22 12:11:50.096 [info] Experiment 'pythonTestAdapter' is active
2024-08-22 12:11:50.096 [error] Reading directory to watch failed [Error: ENOENT: no such file or directory, scandir 'd:\Users\vmosor\Desktop\Work\CWD\.pixi\envs'
	at Object.readdirSync (node:fs:1509:26)
	at t.readdirSync (node:electron/js2c/node_init:2:11418)
	at d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586747
	at d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586938
	at Array.map (<anonymous>)
	at d.initWatchers (d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586656)
	at async d.ensureWatchersReady (d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:543067)] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'scandir',
  path: 'd:\\Users\\vmosor\\Desktop\\Work\\CWD\\.pixi\\envs'
}
2024-08-22 12:11:50.096 [error] Dir "d:\Users\vmosor\Desktop\Work\CWD\.pixi\envs" is not watchable (directory does not exist)
2024-08-22 12:11:50.097 [info] Default formatter is set to null for workspace d:\Users\vmosor\Desktop\Work\CWD
2024-08-22 12:11:50.097 [info] Python interpreter path: C:\Program Files\Python310\python.exe
2024-08-22 12:11:50.161 [info] > pyenv which python
2024-08-22 12:11:50.161 [info] cwd: .
2024-08-22 12:11:53.644 [info] > pixi --version
2024-08-22 12:11:53.646 [error] [Error: spawn pixi ENOENT
	at ChildProcess._handle.onexit (node:internal/child_process:286:19)
	at onErrorNT (node:internal/child_process:484:16)
	at process.processTicksAndRejections (node:internal/process/task_queues:82:21)] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'spawn pixi',
  path: 'pixi',
  spawnargs: [ '--version' ]
}
2024-08-22 12:11:53.646 [warning] could not find a pixi interpreter for the interpreter at C:\Program Files\Python310\python.exe
2024-08-22 12:11:54.614 [warning] could not find a pixi interpreter for the interpreter at C:\Program Files\Python310\python.exe
2024-08-22 12:11:56.089 [info] Starting Pylance language server.

Output for Python in the Output panel - when Pylance v2024.7.1 is installed

2024-08-22 12:16:33.354 [info] Experiment 'pythonaa' is active
2024-08-22 12:16:33.354 [info] Experiment 'pythonRecommendTensorboardExt' is active
2024-08-22 12:16:33.354 [info] Experiment 'pythonREPLSmartSend' is active
2024-08-22 12:16:33.354 [info] Experiment 'pythonTerminalEnvVarActivation' is active
2024-08-22 12:16:33.354 [info] Experiment 'pythonTestAdapter' is active
2024-08-22 12:16:33.354 [error] Reading directory to watch failed [Error: ENOENT: no such file or directory, scandir 'd:\Users\vmosor\Desktop\Work\CWD\.pixi\envs'
	at Object.readdirSync (node:fs:1509:26)
	at t.readdirSync (node:electron/js2c/node_init:2:11418)
	at d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586747
	at d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586938
	at Array.map (<anonymous>)
	at d.initWatchers (d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:586656)
	at async d.ensureWatchersReady (d:\Users\vmosor\.vscode\extensions\ms-python.python-2024.12.3-win32-x64\out\client\extension.js:2:543067)] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'scandir',
  path: 'd:\\Users\\vmosor\\Desktop\\Work\\CWD\\.pixi\\envs'
}
2024-08-22 12:16:33.355 [error] Dir "d:\Users\vmosor\Desktop\Work\CWD\.pixi\envs" is not watchable (directory does not exist)
2024-08-22 12:16:33.355 [info] Default formatter is set to null for workspace d:\Users\vmosor\Desktop\Work\CWD
2024-08-22 12:16:33.355 [info] Python interpreter path: C:\Program Files\Python310\python.exe
2024-08-22 12:16:34.997 [info] > pyenv which python
2024-08-22 12:16:34.998 [info] cwd: .
2024-08-22 12:16:37.617 [info] > pixi --version
2024-08-22 12:16:37.618 [error] [Error: spawn pixi ENOENT
	at ChildProcess._handle.onexit (node:internal/child_process:286:19)
	at onErrorNT (node:internal/child_process:484:16)
	at process.processTicksAndRejections (node:internal/process/task_queues:82:21)] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'spawn pixi',
  path: 'pixi',
  spawnargs: [ '--version' ]
}
2024-08-22 12:16:37.619 [warning] could not find a pixi interpreter for the interpreter at C:\Program Files\Python310\python.exe
2024-08-22 12:16:39.414 [warning] could not find a pixi interpreter for the interpreter at C:\Program Files\Python310\python.exe
2024-08-22 12:16:43.127 [info] Starting Pylance language server.

Extension version: 2024.8.1
VS Code version: Code 1.92.2 (fee1edb8d6d72a0ddff41e5f71a671c23ed924b9, 2024-08-14T17:29:30.058Z)
OS version: Windows_NT x64 10.0.19045
Modes:

System Info
Item Value
CPUs Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz (8 x 2500)
GPU Status 2d_canvas: unavailable_software
canvas_oop_rasterization: disabled_off
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: disabled_software
multiple_raster_threads: enabled_on
opengl: disabled_off
rasterization: disabled_software
raw_draw: disabled_off_ok
skia_graphite: disabled_off
video_decode: disabled_software
video_encode: disabled_software
vulkan: disabled_off
webgl: unavailable_software
webgl2: unavailable_software
webgpu: unavailable_software
webnn: disabled_off
Load (avg) undefined
Memory (System) 31.65GB (20.26GB free)
Process Argv --crash-reporter-id 9c9a4e49-5556-426b-8325-03382243022b
Screen Reader no
VM 0%
A/B Experiments
vsliv368cf:30146710
vspor879:30202332
vspor708:30202333
vspor363:30204092
vscod805cf:30301675
binariesv615:30325510
vsaa593cf:30376535
py29gd2263:31024239
c4g48928:30535728
azure-dev_surveyone:30548225
a9j8j154:30646983
962ge761:30959799
pythongtdpath:30769146
welcomedialogc:30910334
pythonnoceb:30805159
asynctok:30898717
pythonregdiag2:30936856
pythonmypyd1:30879173
h48ei257:31000450
pythontbext0:30879054
accentitlementst:30995554
dsvsc016:30899300
dsvsc017:30899301
dsvsc018:30899302
cppperfnew:31000557
dsvsc020:30976470
pythonait:31006305
dsvsc021:30996838
g316j359:31013175
pythoncenvpt:31062603
a69g1124:31058053
dvdeprecation:31068756
dwnewjupytercf:31046870
impr_priority:31102340
refactort:31108082
pythonrstrctxt:31112756
wkspc-onlycs-t:31111718
wkspc-ranged-t:31118572
ei213698:31121563

@github-actions github-actions bot added the needs repro Issue has not been reproduced yet label Aug 22, 2024
@vcmlseg vcmlseg closed this as not planned Won't fix, can't repro, duplicate, stale Aug 22, 2024
@vcmlseg vcmlseg reopened this Aug 22, 2024
@vcmlseg vcmlseg changed the title The signature help information shown to users for class constructors in Pylance version v2024.8.1 is less useful that in Pylance version Y. This also breaks parameter code completion for those methods. The signature help information shown to users for class constructors in Pylance version v2024.8.1 is less useful that in Pylance version v2024.7.1. This also breaks parameter code completion for those methods. Aug 22, 2024
@rchiodo
Copy link
Contributor

rchiodo commented Aug 22, 2024

Thanks for the issue. I can reproduce. Definitely a regression.

@rchiodo rchiodo added bug Something isn't working regression and removed needs repro Issue has not been reproduced yet labels Aug 22, 2024
@rchiodo
Copy link
Contributor

rchiodo commented Aug 26, 2024

I think this is being caused by a change in Pyright. This code here is returning false when checking if the type returned by __new__ is a subclass of the class FxForwardCurveDefinition.

function shouldSkipInitEvaluation(evaluator: TypeEvaluator, classType: ClassType, newMethodReturnType: Type): boolean {
    const returnType = evaluator.makeTopLevelTypeVarsConcrete(newMethodReturnType);

    let skipInitCheck = false;
    doForEachSubtype(returnType, (subtype) => {
        if (isUnknown(subtype)) {
            return;
        }

        if (isClassInstance(subtype)) {
            const inheritanceChain: InheritanceChain = [];
            const isDerivedFrom = ClassType.isDerivedFrom(subtype, classType, inheritanceChain);

            if (!isDerivedFrom) {
                skipInitCheck = true;
            }

            return;
        }

        skipInitCheck = true;
    });

    return skipInitCheck;
}

@erictraut
Copy link
Contributor

This is due to a bug in the lseg_analytics library's type annotations. The method Model.__new__ (defined on line 518 of the lseg_analytics_basic_client/_model_base.py module) has a return type annotation of Model. It should be typing.Self, since the __new__ method supports subclasses.

The behavior that you're seeing from pyright is dictated by Python typing spec in the chapter on Constructors. This chapter was recently updated to clarify the proper behavior for static type analyzers, and pyright complies with the new rules. That explains why you are seeing a different behavior from earlier versions of pyright and pylance.

I recommend reporting the issue to the maintainers of the lseg_analytics library.

@rchiodo
Copy link
Contributor

rchiodo commented Aug 26, 2024

Specifically changing this line in lseg_analytics_basic_client\_model_base.py

    def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> "Model":  # pylint: disable=unused-argument <-- This return type should say Self
        # we know the last three classes in mro are going to be 'Model', 'dict', and 'object'
        mros = cls.__mro__[:-3][::-1]  # ignore model, dict, and object parents, and reverse the mro order
        attr_to_rest_field: typing.Dict[str, _RestField] = {  # map attribute name to rest_field property
            k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
        }

@rchiodo
Copy link
Contributor

rchiodo commented Aug 26, 2024

@erictraut for the other issue tied to this one:
#6297

User is calling the aws_cdk.aws_lambda.Function constructor which has a MetaClass. The MetaClass __call__ method looks like so:

    def __call__(cls: Type[M], *args: Any, **kwargs) -> M:

Internally that M does not come out as the same as the Function class so we don't use the __init__ for function to find the signature.

AFAICT, the __call__ function on the MetaClass looks correct to me. Isn't that returning the original class?

@erictraut
Copy link
Contributor

#6297 is a different issue, although I can see why you might think they're related. You're correct that the __call__ function on the metaclass is correctly annotated, and this is indeed a bug in pyright. A fix will be included in the next release.

@rchiodo rchiodo added langserver-diff Language server might want to differ from Pyright by design and removed bug Something isn't working regression labels Aug 27, 2024
@rchiodo
Copy link
Contributor

rchiodo commented Aug 27, 2024

Closing as design.

@rchiodo rchiodo closed this as completed Aug 27, 2024
@duncanp-sonar
Copy link

Thanks @rchiodo and @erictraut for investigating and identifying the real issue.

FYI we followed up with the lseg_analytics package authors, and they traced the issue back to a problem in autorest.python which they use to generate their Python package. Apparently the change in Pyright caused a breaking change in autorest.python which has now been fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
by design langserver-diff Language server might want to differ from Pyright
Projects
None yet
Development

No branches or pull requests

4 participants