Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assigning to a slice of a list fails to retain literal values #9564

Open
MageJohn opened this issue Dec 9, 2024 · 3 comments
Open

Assigning to a slice of a list fails to retain literal values #9564

MageJohn opened this issue Dec 9, 2024 · 3 comments
Labels
enhancement request New feature or request

Comments

@MageJohn
Copy link

MageJohn commented Dec 9, 2024

Describe the bug

Assigning to a slice of a list fails to retain literal values

Code or Screenshots

Code sample in pyright playground

from typing import Literal

type Tag = Literal["A", "B"]

l: list[tuple[Tag, str]] = [
    ("A", "foo"),
    ("B", "bar"),
    ("A", "basz")
]

l[0] = ("B", "foo") # works fine

l[0:0] = [("B", "foo")] # fails

VS Code extension or command-line

Are you running pyright as a VS Code extension, a language server in another editor, integrated into Pylance, or the command-line tool? Which version?

I'm running it as a VS Code extension (the code package on Arch Linux). The version is v1.1.390

@MageJohn MageJohn added the bug Something isn't working label Dec 9, 2024
@erictraut erictraut added enhancement request New feature or request and removed bug Something isn't working labels Dec 9, 2024
@erictraut
Copy link
Collaborator

The observed behavior is a consequence of pyright's inference behavior for tuples. It retains literal values for "bare" tuple expressions but does not for tuple expressions that are nested within another container like a list expression.

Normally, bidirectional type inference would help here, but pyright's bidirectional inference logic doesn't currently handle overloaded __setitem__ methods like the one found in the list class.

Adding bidirectional type inference support for overloaded __setitem__ will be a moderate amount of work, but I think it's a reasonable enhancement request.

In the meantime, you can work around this limitation by using a temporary variable with an explicit type declaration.

    temp: list[tuple[Tag, str]] = [("B", "foo")]
    l[0:0] = temp

@MageJohn
Copy link
Author

MageJohn commented Dec 9, 2024

Thanks for the quick response, and the workaround!

@aminakhanum44
Copy link

from typing import Literal, cast

Define the literal type

Tag = Literal["A", "B"]

Define the list with the correct type annotation

l: list[tuple[Tag, str]] = [
("A", "foo"),
("B", "bar"),
("A", "basz"),
]

Assign to an element (this works fine)

l[0] = ("B", "foo")

Workaround 1: Explicitly annotate the new items being inserted

new_items: list[tuple[Tag, str]] = [("B", "foo")]
l[0:0] = new_items

Workaround 2: Use cast to explicitly set the type for the assigned values

l[0:0] = [cast(tuple[Tag, str], ("A", "baz"))]

Verify that the list retains the expected type

print(l) # Output: [('A', 'baz'), ('B', 'foo'), ('A', 'foo'), ('B', 'bar'), ('A', 'basz')]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement request New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants