Динамическая генерация классов с поддержкой автодополненияPython

Программы на Python
Ответить
Anonymous
 Динамическая генерация классов с поддержкой автодополнения

Сообщение Anonymous »

Мне нужно было что-то вроде TypeScript Utilities, но для Pydantic, и я решил сделать это сам, поскольку то, что они предлагают, нужно использовать в качестве словаря, и мне это совсем не нравится, к тому же оно работает только для экземпляров модели, а не сами модели.
Если вам интересно, вы можете проверить это здесь, но оно довольно маленькое, и в этом посте я покажу большую часть кода.
Это буквально все пакет, помимо некоторых методов Dunder, имеет:

Код: Выделить всё

from pydantic import BaseModel, create_model

class ExtendedBaseModel(BaseModel):
"""
A subclass of BaseModel that adds advanced operations for field union, exclusion,
and difference. This class supports bitwise operators (|, &, -) between instances,
where the left instance (self) takes precedence for both values and data types.
"""

@classmethod
def union(cls, _name: str, other: 'ExtendedBaseModel') -> type[BaseModel]:
"""
Creates a new model that merges fields from the current class and another
ExtendedBaseModel class.  In case of overlapping fields, values and data types
from the current model (self) take precedence.

Args:
_name (str): The name for the new model.
other (ExtendedBaseModel): Another model to merge fields with.

Returns:
BaseModel: A new model including fields from both the current class and
the other model.
"""
# Merge annotations from both models, with precedence for the current class
fields_data = {*other.__annotations__.items(), *cls.__annotations__.items()}
# Construct new fields with types and make them required (indicated by `...`)
new_fields = {field: (annotation, ...) for field, annotation in fields_data}
return create_model(_name, **new_fields)

@classmethod
def omit(cls, _name: str, *excluded_fields: str) -> type[BaseModel]:
"""
Exclude specified fields from the current model to create a new model with
only the remaining fields.

Args:
_name (str): The name for the new model.
*excluded_fields (str): Fields to exclude from the model.

Returns:
BaseModel: A new model excluding the specified fields.
"""
# Filter out fields specified in excluded_fields
new_fields = {
field: (cls.__annotations__[field], ...)
for field in cls.__annotations__
if field not in excluded_fields
}
return create_model(_name, **new_fields)

@classmethod
def pick(cls, _name: str, *included_fields: str) -> type[BaseModel]:
"""
Generate a new model with only the specified fields from the current model.

Args:
_name (str): The name for the new model.
*included_fields (str): Fields to include in the new model.

Returns:
BaseModel: A new model containing only the specified fields.
"""
# Select fields specified in included_fields
new_fields = {
field: (cls.__annotations__[field], ...)
for field in cls.__annotations__
if field in included_fields
}
return create_model(_name, **new_fields)
...

Как указано в документации, это подкласс BaseModel Pydantic с некоторыми дополнительными методами и побитовыми операциями, которые позволяют получать подверсии модели или экземпляра модели.
Единственная проблема заключается в том, что Subversion не обеспечивает автодополнение, и мне бы хотелось, чтобы оно делало это в основном для подсказок по типам.
После некоторых исследований я нашел этот пост, в котором я нашел комментарий пользователя igrinis, в котором упоминаются динамически генерируемые файлы .pyi.
Итак, вот какое решение я придумал:

Код: Выделить всё

class ExtendedBaseModel(BaseModel):
...
@classmethod
def generate_pyi(cls, _name: str, fields: dict):
"""
Generate a .pyi file for the dynamically created model to provide type hints to IDEs.

Args:
_name (str): The name of the new model.
fields (dict): A dictionary of field names and types to be included in the .pyi file.
"""
makedirs('types/', exist_ok=True)
pyi_filename = f"types/{_name}.pyi"
with open(pyi_filename, "w") as pyi_file:
pyi_file.write(f"from pydantic import BaseModel\n\n")
pyi_file.write(f"class {_name}(BaseModel):\n")

for field, (field_type, _) in fields.items():
pyi_file.write(f"    {field}: {field_type.__name__}\n")
...

Этот метод работает, но IDE его не распознает. Я не уверен, проблема ли это в моих настройках, или, может быть, я неправильно понял теорию файлов .pyi, так как впервые работаю с ними.


Подробнее здесь: https://stackoverflow.com/questions/791 ... on-support
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»