Как поддержать динамический тип подсказки с метапрограммированием в PyCharm? - PullRequest
0 голосов
/ 31 января 2019

В PyCharm подсказка типа может правильно поддерживать стандартную библиотеку dataclass.Однако, когда я использую тот же агрегат с mydataclass, PyCharm не может это поддерживать:

from dataclasses import dataclass
from typing import Tuple, Dict, TypeVar

_C = TypeVar('_C', bound=type)


class TestORM(type):
    def __new__(cls, clsname: str, bases: Tuple, clsdict: Dict):
        param = ""
        for key, key_type in clsdict.get('__annotations__', {}).items():
            param += f", {key}: {key_type.__name__} = {clsdict.get(key)}"
        clsdict['__init__'] = make_init(param)
        return super().__new__(cls, clsname, bases, clsdict)


@dataclass
class Test:
    a: int = 0


def mydataclass(cls: _C) -> _C:
    param = ""
    for key, key_type in cls.__annotations__.items():
        param += f", {key}: {key_type.__name__} = {getattr(cls, key)}"
    setattr(cls, "__init__", make_init(param))
    return cls


def make_init(param:str):
    locals = {}
    txt = f'def __init__(self{param}):\n   pass'
    exec(txt, None, locals)
    return locals['__init__']


@mydataclass
class MyTest:
    a: int = 0

class MyORMTest(metaclass=TestORM):
    a: int = 0

if __name__ == '__main__':
    Test(a='a')
    MyTest(a='a')
    MyORMTest(a='a')

The actual result in PyCharm

Как мне сделать так, чтобы хинтинг типа PyCharm работал?

Подводя итог, я просто хочу знать, как PyCharm работает с пользовательским классом с dataclass без каких-либо заглушек, относящихся к пользовательскому классу.И когда я использую тот же агрегат, что и dataclass с exec, чтобы сделать мою __init__ функцию динамической, я все равно не могу получить подсказку правильного типа.

PyCharm выполняет какой-то конкретный анализ или проверяет наличиеконкретная библиотека?

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Это странный способ make_init().Почему бы просто не привить реальную функцию?Я предполагаю, что PyCharm потенциально может видеть сквозь setattr, но держу пари, что он не видит сквозь eval.

Например,

def make_init():
  def my_init(self, a:int = 1):  # Should be noted by IDE.
    pass
  return my_init
0 голосов
/ 14 марта 2019

Вы можете использовать стаб-файл, описанный в PEP 561 .Затем в заглушку можно добавлять подписи автоматически создаваемых файлов.

если pyi файл Вы добавляете запись

class MyTest: 
    def __init__(a: int): ...

Тогда у вас будет подсказка типа в PyCharm.

Но я не знаю, как добавить подсказку только для частизаписей из файла.Я прошу об этом здесь: Частичная заглушка в PyCharm

0 голосов
/ 31 января 2019

Python - это динамический язык.Это означает, что объект может быть чем угодно и может быть преобразован во время выполнения.

Некоторые функции, такие как подсказки типов, работа статическим анализом - и набор инструментов Pycharm действительно включал некоторые подсказки подсказок типов, которые также могут проверять Pythonсобственные классы данных с помощью статического анализа.Статический анализ означает: он не связан с «живыми» данными - он выполняется путем просмотра кода и проверки его по подмножеству правил, которые изучаются отдельно от языка.

Короче говоря: естьНЕДОПУСТИМО, чтобы инструменты, используемые Pycharm, могли вывести намеки на типы для произвольного динамического кода.Это просто невозможно.

Если вы создаете обширную инфраструктуру, для которой вам абсолютно необходимо иметь подсказку о статическом типе в IDE, вам придется извлечь источник инструментов, используемых самой IDE.(Я не уверен, что намеки на тип данных в классах данных выполняются самим mypy или каким-либо другим инструментом), и расширяют один из инструментов - или создают свой собственный, который сможет анализировать типы, объявленные в вашей среде,обычным способом вы заявляете тогда.

Иначе этого просто не произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...