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

Pylance flags a reportOptionalMemberAccess for an Optional item in a list even after a test for None #799

Closed
zvongrote opened this issue Jan 3, 2021 · 5 comments
Labels
waiting for user response Requires more information from user

Comments

@zvongrote
Copy link

Environment data

  • Language Server version: 2020.12.2
  • OS and version: macOS 10.15.7
  • Python version (& distribution if applicable, e.g. Anaconda): 3.9.1 installed from homebrew running in venv

Expected behaviour

When using using a list that contains Optional types, no reportOptionalMemberAccess should be reported if the list item is checked to not be None before it's used.

Actual behaviour

When checking a list item to see if it's None using the index operator, a reportOptionalMemberAccess error occurs when trying to use use it from within an "if" block. However, if the list item is first assigned to a variable then checked for None, the error doesn't occur:

image

In cases 1 and 3 the error occurs, but not in cases 2 and 4. This only happens when the Pylance's Type Checking Mode is set to "strict".

Code Snippet / Additional information

from typing import Optional

some_list: list[Optional[str]] = []

some_list.append("test")
some_list.append(None)

blah: Optional[str]

# Case 1
if some_list[0] is not None:
    print(some_list[0].upper())

# Case 2
blah = some_list[0]
if blah is not None:
    print(blah.upper())

# Case 3
if some_list[1] is not None:
    print(some_list[1].upper())

# Case 4
blah = some_list[1]
if blah is not None:
    print(blah.upper())


@github-actions github-actions bot added the triage label Jan 3, 2021
@erictraut
Copy link
Contributor

Pyright (the type checker that underlies pylance) does not perform type narrowing on expressions that contain subscripts. This is by design. There are just too many cases where the values of such expressions can change between the conditional test and the second usage of the expression without the type checker knowing. For example, if you check the first element of a list but then pop and push a value onto the list, the first element will now be different. Type checkers in other languages that offer type narrowing often make the same choice with respect to subscripts.

For a full list of supported type guards (expressions that are narrowed in a conditional statement) in pyright, refer to this documentation.

There is an easy workaround: assign the value of the subscripted expression to a local variable before the test. This not only allows for safe type narrowing, but it also makes the code faster and generally more readable.

first_elem = some_list[0]
if first_elem is not None:
    print(first_elem.upper())

@jakebailey
Copy link
Member

It's been over a month since we marked this issue as waiting for info; if you believe the above fix to not be satisfactory we can reopen, but we do try and follow the typing rules as best as possible.

Note that you can also use the walrus operator in newer versions of python to make the temp var bit a bit cleaner.

See also microsoft/pyright#1494.

@avatar-lavventura
Copy link

@erictraut

if first_elem is not None:
    print(first_elem.upper())

Here is it advices to do following, check with Exception?:

if first_elem is not None:
    print(first_elem.upper())
else:
    raise Exception

@erictraut
Copy link
Contributor

@avatar-lavventura, please don't comment on closed issues. If you think there is a bug present, please open a new issue, and make sure to provide a minimal, self-contained code sample. The sample you've provided above is not complete, so I can't tell what it's trying to demonstrate.

@avatar-lavventura
Copy link

avatar-lavventura commented Mar 14, 2022

I am not presenting any bug. I am just pointing out there is no control made if the first_elem is None.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for user response Requires more information from user
Projects
None yet
Development

No branches or pull requests

5 participants