Skip to content

Value incorrectly flagged as being possibly None after or predicate ensures it isn't None #3508

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

Closed
rowillia opened this issue Jun 7, 2017 · 12 comments
Assignees
Labels
bug mypy got something wrong topic-strict-optional

Comments

@rowillia
Copy link
Contributor

rowillia commented Jun 7, 2017

Invoked with: python3.6 -m mypy --warn-no-return --strict-optional test_or_shortcut.py

from typing import Optional, Any


def test_or_shortcut(value: Optional[Any]) -> None:
    if not value:
        pass
    if not value or value.get('foo') == 'hello':
        pass

Fails with:

test_or_shortcut.py:7: error: Item "None" of "Optional[Any]" has no attribute "get"

Oddly if I remove the first branch things typecheck fine:

from typing import Optional, Any


def test_or_shortcut(value: Optional[Any]) -> None:
    if not value or value.get('foo') == 'hello':
        pass
@gvanrossum
Copy link
Member

Hm, that looks like a binder bug. But I can't repro it. Does it still fail this way in master?

@rowillia
Copy link
Contributor Author

rowillia commented Jun 7, 2017

@gvanrossum Repro'd on HEAD:

rwilliams at rwilliams-mbp114-2 in ~/src/oss/mypy (master●) (venv)
$ python3.6 -m mypy -V
mypy 0.520-dev-72168faf682722ff8ffa6876d3c2fb94a30d5012

@gvanrossum gvanrossum added bug mypy got something wrong topic-strict-optional labels Jun 7, 2017
@gvanrossum
Copy link
Member

Ah, I did'nt copy the flags you are passing. Sorry. Labeled as bug affecting strict-optional.

@ddfisher
Copy link
Collaborator

ddfisher commented Jun 7, 2017

This looks familiar to me -- I think this might be to do with Anys behavior in the subtyping check (or maybe with is_subtype being used instead of is_proper_subtype).

@ddfisher ddfisher self-assigned this Jun 7, 2017
@ddfisher
Copy link
Collaborator

ddfisher commented Jun 7, 2017

I was wrong -- it's actually related to truthiness tracking. For some reason, after the if not value: pass, the Any part of the union has can_be_true set to False.

@gvanrossum
Copy link
Member

What if there is something other than pass in the first if block?

@ddfisher
Copy link
Collaborator

ddfisher commented Jun 7, 2017

I was wondering that too. I tried replacing the pass with an unrelated assignment statement -- the problem persisted.

@ddfisher
Copy link
Collaborator

ddfisher commented Jun 8, 2017

Okay, I think I've tracked this down to the root cause of the problem: true_or_false (in types.py) doesn't behave correctly on Unions. In particular, it sets can_be_true and can_be_false to True on the Union type, but not on any of its items!

@lk-geimfari
Copy link

lk-geimfari commented Nov 22, 2017

I have the same problem, but with enums

Here is my enum object:

class AllowRandom(EnumMeta):

    def get_random_item(self) -> enum.Enum: # but i'm not sure
        return choice(list(self))

class PrefixSign(enum.Enum, metaclass=AllowRandom):
    POSITIVE = 'positive'
    NEGATIVE = 'negative'

and when i tried this:

def prefix(sign: Optional[PrefixSign] = None) -> str:
    prefixes = {
        'negative': ['...'],
        'positive': ['...'],
    }

    if sign is None:
        sign = PrefixSign.get_random_item()

    if sign in PrefixSign:
        return self.random.choice(prefixes[sign.value])
    else:
        raise NonEnumerableError(PrefixSign)

I got this:

project/test.py:24: error: Item "None" of "Optional[PrefixSign]" has no attribute "value"
project/units.py:25: error: Item "None" of "Optional[PrefixSign]" has no attribute "value"

How to deal with this?

@ilevkivskyi
Copy link
Member

@lk-geimfari I think your particular case may be related to the fact that the method get_random_item() is not annotated. If I am right, then this should be fixed by the last commit. Could you please try your code with the current mypy master?

@lk-geimfari
Copy link

lk-geimfari commented Nov 22, 2017

@ilevkivskyi Unfortunately, it's did not help. I have updated the code which i write, please look above. The problem that i don't know which subclass of Enum will be returned and when i try annotate get_random_item, here even more errors:

project/units.py:24: error: Incompatible types in assignment (expression has type "Enum", variable has type "Optional[PrefixSign]")
project/units.py:25: error: Item "None" of "Optional[PrefixSign]" has no attribute "value"

@ilevkivskyi
Copy link
Member

@lk-geimfari You can try self-types instead of just returning Enum.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-strict-optional
Projects
None yet
Development

No branches or pull requests

5 participants