Pyright hangs forever on a namedtuple with classmethod constructor
- Dominant language
- Python
- Stars
- 15.6k
- Forks
- 1.8k
- Avg merge
- 12h 13m
- Merged PRs (30d)
- 52
Description
**Describe the bug**
See the title and the code snippet below.
Here is the story; vscode with pylance as LSP started getting really slow to report typing violations and provide LSP services like semantic highlighting and the fans of my PC are spinning continuously. I ran pyright from the command line to see if the problem is caused by pyright or a pylance-specific feature and the culprit turned out to be pyright. I was able to narrow down the problem to a single class which I simplified and anonymized and included in the snippet below.
**Code or Screenshots**
```python
from typing import NamedTuple, Self
class Field1(int): ...
class Field2(int): ...
class Field3(int): ...
class Field6(int): ...
class Field7(int): ...
class Field8(int): ...
class Field9(int): ...
class Field10(int): ...
class Field11(int): ...
class Field12(int): ...
class Field13(int): ...
class Field15(int): ...
class Field16(int): ...
class Field17(int): ...
class Field18(int): ...
class Register(NamedTuple):
field1: Field1
field2: Field2
field3: Field3
flag4: bool
flag5: bool
field6: Field6
field7: Field7
field8: Field8
field9: Field9
field10: Field10
field11: Field11
field12: Field12
field13: Field13
flag14: bool
field15: Field15
field16: Field16
field17: Field17
field18: Field18
# This method chokes pyright
@classmethod
def fromhex(cls, string: str, /) -> Self:
n = int(string, 16)
return cls(
field1=Field1(n & 0b1),
field2=Field2((n := n >> 1) & 0b111),
field3=Field3((n := n >> 3) & 0b01),
flag4=bool((n := n >> 2) & 0b1),
flag5=bool((n := n >> 1) & 0b1),
field6=Field6((n := n >> 1) & 0b1),
field7=Field7((n := n >> 1) & 0b1),
field8=Field8((n := n >> 1) & 0b1111),
field9=Field9((n := n >> 4) & 0b11),
field10=Field10((n := n >> 2) & 0b1),
field11=Field11((n := n >> 1) & 0b01),
field12=Field12((n := n >> 2) & 0b11),
field13=Field13((n := n >> 2) & 0b11),
flag14=bool((n := n >> 2) & 0b1),
field15=Field15((n := n >> 1) & 0b11),
field16=Field16((n := n >> 2) & 0b11),
field17=Field17((n := n >> 2) & 0b11),
field18=Field18((n := n >> 2) & 0b11),
)
```
This code snippet hangs forever (I killed pyright after 22 minutes). Note that pyright did *sometimes* finish analyzing the original code before simplification in about 50 seconds but it always hangs for me with this snippet. Another thing I noticed is that if I assign the arguments to `cls` to local variables pyright finishes in about 0.6 seconds:
```python
# replace fromhex with this to get pyright to finish analyzing
@classmethod
def fromhex(cls, string: str, /) -> Self:
n = int(string, 16)
field1 = Field1(n & 0b1)
field2 = Field2((n := n >> 1) & 0b111)
field3 = Field3((n := n >> 3) & 0b01)
flag4 = bool((n := n >> 2) & 0b1)
flag5 = bool((n := n >> 1) & 0b1)
field6 = Field6((n := n >> 1) & 0b1)
field7 = Field7((n := n >> 1) & 0b1)
field8 = Field8((n := n >> 1) & 0b1111)
field9 = Field9((n := n >> 4) & 0b11)
field10 = Field10((n := n >> 2) & 0b1)
field11 = Field11((n := n >> 1) & 0b01)
field12 = Field12((n := n >> 2) & 0b11)
field13 = Field13((n := n >> 2) & 0b11)
flag14 = bool((n := n >> 2) & 0b1)
field15 = Field15((n := n >> 1) & 0b11)
field16 = Field16((n := n >> 2) & 0b11)
field17 = Field17((n := n >> 2) & 0b11)
field18 = Field18((n := n >> 2) & 0b11)
return cls(
field1=field1,
field2=field2,
field3=field3,
flag4=flag4,
flag5=flag5,
field6=field6,
field7=field7,
field8=field8,
field9=field9,
field10=field10,
field11=field11,
field12=field12,
field13=field13,
flag14=flag14,
field15=field15,
field16=field16,
field17=field17,
field18=field18,
)
```
It is been a few months since I opened this project in vscode so I'm not sure which version of pyright regressed and I didn't bisect either.
**VS Code extension or command-line**
Both. Latest pylance pre-release and pyright 1.1.402
Contributor guide
Research direction
Start with the supplied minimal NamedTuple and fromhex reproduction using pyright 1.1.402, then compare analysis of the inline constructor arguments with the version assigning them to locals. Done means the inline version completes analysis promptly rather than hanging indefinitely, while preserving the reported behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100