mypy Error TypeVar с ограничением значения и объединением союзов / Необязательно Не удается передать универсальный тип контейнера - PullRequest
0 голосов
/ 28 ноября 2018

Итак, следующий пример явно надуманный, но я попытался сохранить правдоподобие моей реальной ситуации.Теперь, когда я сократил это, я уверен, что упускаю что-то очевидное.Рассмотрим пару типов и ограниченный союз:

from typing import Union, TypeVar, Optional, Generic, overload

class Foo:
    def __init__(self, x: int)-> None:
        self.x = x
    def frobnicate(self) -> 'Foo':
        return Foo((self.x + 42) // 42)

class Bar:
    def __init__(self, y: int) -> None:
        self.y = y
    def frobnicate(self) -> 'Bar':
        return Bar(self.y + 88)

MyType = TypeVar('MyType', Foo, Bar)
class Container(Generic[MyType]):
    val: Optional[MyType]
    def __init__(self, val: Optional[MyType]=None) -> None:
        self.val = val

def transmogrify(arg: Optional[MyType]) -> Optional[MyType]:
    if arg is None:
        return None
    else:
        return arg.frobnicate()

def extract_stuff(x: Optional[int], cont: Container[MyType]) -> Optional[MyType]:
    result: Optional[MyType]
    if x is None:
        result = None
    elif x == 88 or x == 42:
        result = transmogrify(cont.val)
    else:
        result = cont.val
    return result

Когда я пытаюсь проверить это с помощью mypy, я получаю следующие ошибки:

mcve3.py:32: error: Value of type variable "MyType" of "transmogrify" cannot be "Optional[Foo]"
mcve3.py:32: error: Value of type variable "MyType" of "transmogrify" cannot be "Optional[Bar]"

Я не могу понятьэтот.Я подозреваю, что это проблема многих вложенных союзов?Обратите внимание, что в моем собственном коде я использую собственное одноэлементное перечисление Null, поэтому везде, где вы видите Optional[Something], это на самом деле Union[Something, Null], но я не думаю, что это имеет значение.

Теперь,если я удаляю Optional, то есть Union, все это звучит хорошо:

from typing import Union, TypeVar, Optional, Generic, overload

class Foo:
    def __init__(self, x: int)-> None:
        self.x = x
    def frobnicate(self) -> 'Foo':
        return Foo((self.x + 42) // 42)

class Bar:
    def __init__(self, y: int) -> None:
        self.y = y
    def frobnicate(self) -> 'Bar':
        return Bar(self.y + 88)

MyType = TypeVar('MyType', Foo, Bar)
class Container(Generic[MyType]):
    val: MyType
    def __init__(self, val: MyType) -> None:
        self.val = val

def transmogrify(arg: MyType) -> MyType:
    if arg is None:
        return None
    else:
        return arg.frobnicate()

def extract_stuff(x: int, cont: Container[MyType]) -> MyType:
    if x is None:
        return None
    elif x == 88 or x == 42:
        return transmogrify(cont.val)
    else:
        return cont.val

Чего мне не хватает в Union здесь?

Обратите внимание, я попытался абстрагироватьбазовый класс и наличие Foo и Bar происходит от абстрактного базового класса class MyType(metaclass=abc.Meta), но появляется очень похожая ошибка.

Редактировать, чтобы добавить:

(py37) Juans-MBP: juan$ mypy --version
mypy 0.620

1 Ответ

0 голосов
/ 29 ноября 2018

Кажется, это ошибка, которая была исправлена ​​в mypy.Я смог воспроизвести проблему в вашем первом фрагменте, используя mypy 0.630, но не смог воспроизвести и mypy 0.641, и последнюю версию mypy на master.

Я очень подозрительно подозреваю, что ошибка была исправлена ​​https://github.com/python/mypy/pull/5699,, но не знаю наверняка (и не хочу проверять, tbh).

Вы можете отслеживать блог mypy , если хотите получать уведомления о будущемрелизы, чтобы избежать подобных ситуаций в будущем.Новые выпуски выпускаются примерно каждые 6 недель или около двух месяцев.- следующий релиз должен выйти примерно через две недели с момента написания.

...