Skip to content

Literal typehint on parameter in __init__ does not propagate to class instance attribute #11287

@pydsigner

Description

@pydsigner

Describe the bug
When an __init__ method takes a Literal-typed parameter, an attribute set to that parameter argument will only be inferred as the Literal type until the end of the method. Elsewhere in the class, it will be widened to the generic type. Potentially related to #11286?

Code or Screenshots

import typing as t

NumName = t.Literal['a', 'b']
NUM_DICT: dict[NumName, int] = {
    'a': 1,
    'b': 2,
}

def get_num(name: NumName) -> int:
    return NUM_DICT[name]

class X1:
    def __init__(self, name: NumName):
        self.name: NumName = name
        get_num(self.name)

    def later(self):
        get_num(self.name)

class X2:
    def __init__(self, name: NumName):
        self.name = name
        get_num(self.name)

    def later(self):
        get_num(self.name)

What I expect is for both X1 and X2 to check successfully. What I get instead is that only X1 passes, while X2 fails:

test.py:26:17 - error: Argument of type "str" cannot be assigned to parameter "name" of type "NumName" in function "get_num"
    Type "str" is not assignable to type "NumName"
      "str" is not assignable to type "Literal['a']"
      "str" is not assignable to type "Literal['b']" (reportArgumentType)

It is undesirable to duplicate the typehint from the parameter into the attribute initialization boilerplate.

VS Code extension or command-line
I am running pyright 1.1.408 from the command-line.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions