microsoft / microsoft/pyright

Wrong type interference for inheritance with statements

Open
#10,934 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

I'm developing a proprietary python plugin using pyo3 to ease software testing for embedded deviced. It's somewhat like the ctypes plugin but provides more capabilites for our specific needs.

For array creation i can use ctypes like:
Image
For both variants the inherited type is properly interfered as type[Array[c_ubytes]].

When trying to do the same with my plugin:
Image
The first variant works as the type of BaseClass2 is properly interfered as U8Array. The second variant seems to inerhit from U8 instead of U8Array so the \_\_get_item__ method is apparently not available.

The runtime works as expected. The error both appears with the vscode pylance plugin and when running pyright 1.1.405 from the commandline.

While most of the classes is defined in rust, the metaclass logic inside the \_\_init__.py file looks like this (_types.U8 being the rust class):

```python
class _ArrayAble(Protocol):
@classmethod
def __make_array__[C](cls: type[C], size: int) -> Any: ...

class _U8ArrayMeta(type):
def __getitem__[C: _ArrayAble](cls: type[C], size: int) -> type[U8Array]:
return cls.__make_array__(size)

class U8(_types.U8, metaclass=_U8ArrayMeta): ...
```

I also provide a stub file (\_\_init__.pyi), which is what pyright seems to use for its type interference:

```python
class _NonGeneric:
def __class_getitem__(cls, index: int) -> None: ...

class _ArrayAble(Protocol):
@classmethod
def __make_array__[C](cls: type[C], size: int) -> Any: ...

class U8Array(ArrayType):
"""
8-Bit Unsigned Integer implementing `pymat.types.protocols.ArrayType` and
`pymat.types.protocols.MeterVariable`
"""

class _U8ArrayMeta(type):
def __getitem__[C: _ArrayAble](cls: type[C], size: int) -> type[U8Array]: ...

class U8(PrimitiveType, _NonGeneric, metaclass=_U8ArrayMeta):
"""
8-Bit Unsigned Integer implementing `pymat.types.protocols.PrimitiveType` and
`pymat.types.protocols.MeterVariable`
"""
```
The ArrayType class provides the inherited \_\_get_item__ method:

```python
class ArrayType(MeterVariable):
def __getitem__(self, idx: int) -> PrimitiveTypeProtocol:
....
```

Contributor guide

Open the contributing guide

Research direction

Start with the supplied _ArrayAble, _U8ArrayMeta, U8, U8Array, and ArrayType definitions and reproduce the result with pyright 1.1.405 from the command line. Trace the inheritance handling for the metaclass subscription and verify that the inherited type is resolved as U8Array, with ArrayType.__getitem__ available in both variants.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.