pyright icon indicating copy to clipboard operation
pyright copied to clipboard

Incorrect "variable is not accessed" message

Open jdayton3 opened this issue 6 months ago • 2 comments

Environment data

  • Language Server version: 2024.8.1
  • OS and version: win32 x64
  • Python version (and distribution if applicable, e.g. Anaconda): Python 3.8.10, in venv
  • python.analysis.indexing: true
  • python.analysis.typeCheckingMode: strict

Code Snippet

# pyright: strict
from functools import partial
from dataclasses import dataclass

@dataclass
class Dog:
    name: str
    breed: str

def partial_dog(breed: str):
    formatted_breed = breed.title() # error: Variable "formatted_breed" is not accessed

    return partial(
        Dog,
        breed=f"Maybe a {formatted_breed}", # but it's accessed right here
    )

if __name__ == "__main__":
    print(partial_dog("beagle")(name="Buddy"))
C:\Users\jdayton\source\temp> python .\repro.py   
Dog(name='Buddy', breed='Maybe a Beagle')

Expected behavior

When using a function-local variable in an f-string as a dataclass constructor argument in functools.partial, Pylance should recognize that the variable is being accessed.

Actual behavior

Pylance reports the function-local variable as unused.

We get the same error when running pyright (pyright==1.1.377, installed with pip) in the terminal:

C:\Users\jdayton\source\temp> pyright .\repro.py
c:\Users\jdayton\source\temp\repro.py
  c:\Users\jdayton\source\temp\repro.py:11:5 - error: Variable "formatted_breed" is not accessed (reportUnusedVariable)
1 error, 0 warnings, 0 informations

We also get this error if Dog is a pydantic BaseModel:

from pydantic import BaseModel # pydantic==2.7.4

class Dog(BaseModel):
    name: str
    breed: str

We don't get this error if Dog is a regular class:

class Dog:
    def __init__(self, name: str, breed: str):
        self.name = name
        self.breed = breed

We also don't get the error if formatted_breed is passed in directly, not in an f-string:

def partial_dog(breed: str):
    formatted_breed = f"Maybe a {breed.title()}"

    return partial(
        Dog,
        breed=formatted_breed,
    )

If the variable in the f-string is a parameter instead of a local variable, we don't get this error, but Pylance sometimes can't tell what its type is:

image

jdayton3 avatar Aug 22 '24 17:08 jdayton3