invalid-inheritance on a call-expression base class even when the callable returns type[...] (mixin factory)
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 516
- PR merge metrics
- No merged PRs in 30d
Description
### Summary
Pyrefly reports `invalid-inheritance` ("Invalid expression form for base class") for a base class that is a **call expression**, even when the callable is annotated to return a class type (`type[...]`). This "mixin factory" pattern is valid Python and is accepted by both mypy and pyright.
### Repro
`pyrefly.toml`:
```toml
project-includes = ["m.py"]
```
`m.py`:
```python
class Mixin: ...
def factory(name: str) -> type[Mixin]: ...
class C(factory("x")): # <-- flagged
pass
```
`pyrefly check` (v1.0.0):
```
ERROR Invalid expression form for base class: `factory("x")` [invalid-inheritance]
```
### Expected
No error. `factory("x")` has type `type[Mixin]`, which is a valid base class. mypy and pyright both accept this.
### Real-world motivation
`django_prometheus`'s `ExportModelOperationsMixin(model_name)` returns a dynamically-built mixin class, used as:
```python
class User(ExportModelOperationsMixin("user"), AbstractUser): ...
```
Every model using this factory gets a spurious `invalid-inheritance`. (django_prometheus is untyped so the call returns `Any` in that case — but as the repro above shows, the error fires even when the factory is fully typed to return `type[Mixin]`.)
### Note
The same `m.py` checked with **no config** (the `basic` preset) reports **0 errors** — the error only appears under a project config. So pyrefly can evidently accept the form in one mode but not the other.
### Environment
- pyrefly 1.0.0 (also reproduced on 1.1.1)
- Python 3.12
Contributor guide
Assessment
This issue has not been assessed yet.