-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Bug Report
I wanted to make an item class with multiple descriptor-'variant' attributes (optional-strings). Any of these attr's could be null/empty, but AT LEAST ONE of them needs to be defined (i.e. a non-empty string). And I want a read-only property that should return the 'primary' descriptor-value (as string), or raise an err if no descriptors are defined.
In the simplified example below, I implemented this logic for two descriptor-variants, in two seemingly-equivalent ways, but for some reason MyPy yields an error in the first approach but not the second.
To Reproduce
from typing import Optional
class Item_V1:
descriptor_variant1: Optional[str]
descriptor_variant2: Optional[str]
# ... followed by any number of other arbitrary attr's that we don't care about.
@property
def primary_descriptor(self) -> str:
if not self.descriptor_variant1 and not self.descriptor_variant2:
raise AttributeError("At least one item-descriptor variant must be defined.")
if not self.descriptor_variant1:
return self.descriptor_variant2
return self.descriptor_variant1
class Item_V2:
descriptor_variant1: Optional[str]
descriptor_variant2: Optional[str]
@property
def primary_descriptor(self) -> str:
if not self.descriptor_variant1:
if not self.descriptor_variant2:
raise AttributeError("At least one item-descriptor variant must be defined.")
return self.descriptor_variant2
return self.descriptor_variant1
MyPy Output
I believe that the primary_descriptor
property for both Item_V1
and Item_V2
should be evaluated without errors by MyPy; however, in reality, l.13 in the Item_V1
approach yields MyPy error "Incompatible return value type (got "Optional[str]", expected "str") [return-value]", whereas the equivalent return-statement for Item_V2
(l.26) is evaluated as correct.
Your Environment
- Python version used: 3.9 [but tested up to v3.12 using https://mypy-play.net/]
- Mypy version used: 1.6.1 [but tested up to v1.9.0 using https://mypy-play.net/]
- Mypy command-line flags: N/A
- Mypy configuration options from
mypy.ini
(and other config files): nothing relevant
Caveats/Disclaimers
- Whilst in theory the
Item_V2
method is fine for my current scenario, in an ideal world I would prefer to be able to the use theItem_V1
-type sequence, as otherwise this would lead to an n-level nested if-statement, which seems like bad style, and would become unwieldy as num. descriptor variants increases. And mostly I just don't understand why there is any difference in MyPy's behaviour... - Before anyone asks something of the form: why not store the descriptor variants using an Iterable/dict? - the actual use-case here is in a Django model, where each descriptor variant needs to map to a nullable/blank-able CharField. But that's not really relevant to the error state, in any case.