Автодополнение кода и проверка типов для boto3
- вторник, 4 февраля 2020 г. в 00:24:06
Картинка предоcтавлена автором boto3-type-annotations, Allie Fitter
Сейчас мало кто пишет большие проекты на Python без аннотации типов. Это и просто, и позволяет отловить кучу ошибок еще на этапе написания кода, да и работает очень шустро. Но стоит добавить в зависимости boto3, и mypy начинает пестрить сообщениями о том, что аннотаций типов для boto3
не существует в природе.
Не страшно, существует же официальный генератор аннотаций для boto3 botostubs. Только он официально не выпускался, не обновляется и с mypy
не работает.
Есть и замечательный boto3-type-annotations, но тоже немного заброшен, и поддержки mypy
всё еще нет.
Как же проверять типы для boto3
, а бонусом получить автодополнение кода?
Предположим, мы пользуемся самой свежей на данный момент версией boto3 1.11.9
для сервисов EC2, DynamoDB и S3. Да и Python у нас 3.6.9 или даже новее. Чтобы получить и проверку типов, и автодополнение, нам нужно установить совместимую версию boto3-stubs 1.11.9.x с указанием сервисов.
# поддерживаются все boto3 сервисы, так что замените на свои
pip install boto3-stubs[s3,ec2,dynamodb]==1.11.9.0
# если вы не используете pip, pipfile или poetry,
# или же устанавливаете whl-пакеты, то нужно еще и сгенерировать
# индекс установленных сервисов
python -m mypy_boto3
И… всё! Уже можно запускать mypy
и увидеть, что он, наконец, нашел стабы для boto3
, а возможно даже нашел ошибки в проекте.
И это тоже есть, но уже чуть сложнее.
В VSCode не поддерживаются полностью аннотации для перегруженных функций, так что типы в некоторых случаях придется указывать явно. А именно для boto3.client
, boto3_session.client
,boto3.resource
, boto3_session.resource
, client.get_waiter
и client.get_paginator
.
В PyCharm авто-определение типов для перегруженных функций может медленно работать и поедать оперативку, если вы установили больше 15 сервисов, так что явные типы пригодятся и там.
import boto3
from mypy_boto3 import dynamodb
# Явное указание типа, чтобы автодополнение работало везде
client: dynamodb.DynamoDBClient = boto3.client("dynamodb")
# IDE подскажет имена и типы агрументов и возвращаемого значения
client.query("my_table")
import boto3
from mypy_boto3 import s3
# PyCharm и mypy работают и без явного указания типа, но лучше указывать
client: s3.S3Client = boto3.client("s3")
# IDE подсказывает и имена, и типы, и всё-всё-всё
client.create_bucket(Bucket="bucket")
# посмотрим, сможет ли mypy отловить ошибки в этом коде
# (mypy) error: Missing positional argument "Key" in call to "get_object" of "S3Client"
client.get_object(Bucket="bucket")
# (mypy) error: Argument "Key" to "get_object" of "S3Client" has incompatible type "None"; expected "str"
client.get_object(Bucket="bucket", Key=None)
resource: s3.S3ServiceResource = boto3.Session(region_name="us-west-1").resource("s3")
# Для ресурсов авто-дополенение и проверка типов тоже работает
bucket = resource.Bucket("bucket")
# (mypy) error: Unexpected keyword argument "key" for "upload_file" of "Bucket"; did you mean "Key"?
bucket.upload_file(Filename="my.txt", key="my-txt")
# waiter'ы и paginator'ы тоже аннотированы
# и не забываем про явные типы на всякий случай
waiter: s3.BucketExistsWaiter = client.get_waiter("bucket_exists")
paginator: s3.ListMultipartUploadsPaginator = client.get_paginator(
"list_multipart_uploads"
)
Аннотации создаются автоматически небольшой библиотекой mypy-boto3-builder и выходят спустя час-два после релиза новой версии boto3
. Если вы используете старую версию boto3
, то можете сгенерировать пакеты руками по инструкции.
Гененриуется это всё из json
-файлов с описанием сервисов из botocore с небольшими патчами, так как boto3
изменяет методы некоторых сервисов.
Напоследок, несколько вопросов для вас, чтобы размять мозги и при этом помочь проекту.
Для генерации индекса аннотаций для сервисов используется post-install скрипт, который сам по себе грязный хак и не поддерживается в whl-пакетах. Есть ли способ избежать этого?
Так как в boto3
многие методы и классы в одном файле называются одинаково, для корректной работы аннотаций модуль импортирует сам себя. Это не работает в Python 3.6.5 и выглядит не очень. Какие есть альтернативы?
Ну и, наконец, если у вас все в порядке с C#, можно добавить поддержку литералов в перегруженные функции для Python Language Server, чтобы в VSCode всё тоже работало из коробки. Я не смог и сдался.
Всем спасибо!