youtype / mypy_boto3_builder

Type annotations builder for boto3 compatible with VSCode, PyCharm, Emacs, Sublime Text, pyright and mypy.
https://youtype.github.io/mypy_boto3_builder/
MIT License
544 stars 36 forks source link

Client package ServiceName literal definitions are not necessarily up-to-date #231

Closed jvtm closed 10 months ago

jvtm commented 11 months ago

Describe the bug

Issue:

Additionally it looks like that installing a specific version of boto3-stubs[service] does not necessarily give the matching or even latest version of mypy-boto3-service. It's therefore quite useless to have a line like this in Poetry style pyproject.toml:

boto3-stubs = {version = "^1.28.71", extras = ["cloudfront", "s3"]}

This might leave you with mypy-boto3-cloudfront and mypy-boto3-s3 bot being version 1.28.0 , while they should perhaps be the latest (at that point in time: mypy-boto3-cloudfront==1.28.36, mypy-boto3-s3==1.28.55).

But this is not why I created this report, just noticed that it was quite odd, and got me a bit confused while debugging the actual issue.

To Reproduce Steps to reproduce the behavior:

  1. Install boto3-stubs[s3] and latest boto3

    boto3==1.28.71
    boto3-stubs==1.28.71
    botocore==1.31.71
    botocore-stubs==1.31.71
    mypy-boto3-cloudfront==1.28.36
  2. Run mypy on the following code sample

from __future__ import annotations

from functools import cached_property
from typing import TYPE_CHECKING

import boto3

if TYPE_CHECKING:
    from mypy_boto3_s3 import S3Client
    from mypy_boto3_s3.literals import ServiceName

class AWSAccess:
    def __init__(self):
        # Some common setup like logging, access rights, etc here.
        # This is a stripped down version for pointing out boto3-stubs related bug.
        pass

    @staticmethod
    def client(service: ServiceName, **kwargs):
        return boto3.client(service, **kwargs)

    @cached_property
    def s3(self) -> S3Client:
        return self.client("s3")

Actual output

$ mypy claws.py
claws.py:21: error: Argument 1 to "client" has incompatible type "Literal['accessanalyzer', 'account', 'acm', 'acm-pca', 'alexaforbusiness', 'amp', 'amplify', 'amplifybackend', 'amplifyuibuilder', 'apigateway', 'apigatewaymanagementapi', 'apigatewayv2', 'appconfig', 'appconfigdata', 'appfabric', 'appflow', 'appintegrations', 'application-autoscaling', 'application-insights', 'applicationcostprofiler', 'appmesh', 'apprunner', 'appstream', 'appsync', 'arc-zonal-shift', 'athena', 'auditmanager', 'autoscaling', 'autoscaling-plans', 'backup', 'backup-gateway', 'backupstorage', 'batch', 'billingconductor', 'braket', 'budgets', 'ce', 'chime', 'chime-sdk-identity', 'chime-sdk-media-pipelines', 'chime-sdk-meetings', 'chime-sdk-messaging', 'chime-sdk-voice', 'cleanrooms', 'cloud9', 'cloudcontrol', 'clouddirectory', 'cloudformation', 'cloudfront', 'cloudhsm', 'cloudhsmv2', 'cloudsearch', 'cloudsearchdomain', 'cloudtrail', 'cloudtrail-data', 'cloudwatch', 'codeartifact', 'codebuild', 'codecatalyst', 'codecommit', 'codedeploy', 'codeguru-reviewer', 'codeguru-security', 'codeguruprofiler', 'codepipeline', 'codestar', 'codestar-connections', 'codestar-notifications', 'cognito-identity', 'cognito-idp', 'cognito-sync', 'comprehend', 'comprehendmedical', 'compute-optimizer', 'config', 'connect', 'connect-contact-lens', 'connectcampaigns', 'connectcases', 'connectparticipant', 'controltower', 'cur', 'customer-profiles', 'databrew', 'dataexchange', 'datapipeline', 'datasync', 'dax', 'detective', 'devicefarm', 'devops-guru', 'directconnect', 'discovery', 'dlm', 'dms', 'docdb', 'docdb-elastic', 'drs', 'ds', 'dynamodb', 'dynamodbstreams', 'ebs', 'ec2', 'ec2-instance-connect', 'ecr', 'ecr-public', 'ecs', 'efs', 'eks', 'elastic-inference', 'elasticache', 'elasticbeanstalk', 'elastictranscoder', 'elb', 'elbv2', 'emr', 'emr-containers', 'emr-serverless', 'entityresolution', 'es', 'events', 'evidently', 'finspace', 'finspace-data', 'firehose', 'fis', 'fms', 'forecast', 'forecastquery', 'frauddetector', 'fsx', 'gamelift', 'gamesparks', 'glacier', 'globalaccelerator', 'glue', 'grafana', 'greengrass', 'greengrassv2', 'groundstation', 'guardduty', 'health', 'healthlake', 'honeycode', 'iam', 'identitystore', 'imagebuilder', 'importexport', 'inspector', 'inspector2', 'internetmonitor', 'iot', 'iot-data', 'iot-jobs-data', 'iot-roborunner', 'iot1click-devices', 'iot1click-projects', 'iotanalytics', 'iotdeviceadvisor', 'iotevents', 'iotevents-data', 'iotfleethub', 'iotfleetwise', 'iotsecuretunneling', 'iotsitewise', 'iotthingsgraph', 'iottwinmaker', 'iotwireless', 'ivs', 'ivs-realtime', 'ivschat', 'kafka', 'kafkaconnect', 'kendra', 'kendra-ranking', 'keyspaces', 'kinesis', 'kinesis-video-archived-media', 'kinesis-video-media', 'kinesis-video-signaling', 'kinesis-video-webrtc-storage', 'kinesisanalytics', 'kinesisanalyticsv2', 'kinesisvideo', 'kms', 'lakeformation', 'lambda', 'lex-models', 'lex-runtime', 'lexv2-models', 'lexv2-runtime', 'license-manager', 'license-manager-linux-subscriptions', 'license-manager-user-subscriptions', 'lightsail', 'location', 'logs', 'lookoutequipment', 'lookoutmetrics', 'lookoutvision', 'm2', 'machinelearning', 'macie', 'macie2', 'managedblockchain', 'managedblockchain-query', 'marketplace-catalog', 'marketplace-entitlement', 'marketplacecommerceanalytics', 'mediaconnect', 'mediaconvert', 'medialive', 'mediapackage', 'mediapackage-vod', 'mediapackagev2', 'mediastore', 'mediastore-data', 'mediatailor', 'medical-imaging', 'memorydb', 'meteringmarketplace', 'mgh', 'mgn', 'migration-hub-refactor-spaces', 'migrationhub-config', 'migrationhuborchestrator', 'migrationhubstrategy', 'mobile', 'mq', 'mturk', 'mwaa', 'neptune', 'neptunedata', 'network-firewall', 'networkmanager', 'nimble', 'oam', 'omics', 'opensearch', 'opensearchserverless', 'opsworks', 'opsworkscm', 'organizations', 'osis', 'outposts', 'panorama', 'payment-cryptography', 'payment-cryptography-data', 'pca-connector-ad', 'personalize', 'personalize-events', 'personalize-runtime', 'pi', 'pinpoint', 'pinpoint-email', 'pinpoint-sms-voice', 'pinpoint-sms-voice-v2', 'pipes', 'polly', 'pricing', 'privatenetworks', 'proton', 'qldb', 'qldb-session', 'quicksight', 'ram', 'rbin', 'rds', 'rds-data', 'redshift', 'redshift-data', 'redshift-serverless', 'rekognition', 'resiliencehub', 'resource-explorer-2', 'resource-groups', 'resourcegroupstaggingapi', 'robomaker', 'rolesanywhere', 'route53', 'route53-recovery-cluster', 'route53-recovery-control-config', 'route53-recovery-readiness', 'route53domains', 'route53resolver', 'rum', 's3', 's3control', 's3outposts', 'sagemaker', 'sagemaker-a2i-runtime', 'sagemaker-edge', 'sagemaker-featurestore-runtime', 'sagemaker-geospatial', 'sagemaker-metrics', 'sagemaker-runtime', 'savingsplans', 'scheduler', 'schemas', 'sdb', 'secretsmanager', 'securityhub', 'securitylake', 'serverlessrepo', 'service-quotas', 'servicecatalog', 'servicecatalog-appregistry', 'servicediscovery', 'ses', 'sesv2', 'shield', 'signer', 'simspaceweaver', 'sms', 'sms-voice', 'snow-device-management', 'snowball', 'sns', 'sqs', 'ssm', 'ssm-contacts', 'ssm-incidents', 'ssm-sap', 'sso', 'sso-admin', 'sso-oidc', 'stepfunctions', 'storagegateway', 'sts', 'support', 'support-app', 'swf', 'synthetics', 'textract', 'timestream-query', 'timestream-write', 'tnb', 'transcribe', 'transfer', 'translate', 'verifiedpermissions', 'voice-id', 'vpc-lattice', 'waf', 'waf-regional', 'wafv2', 'wellarchitected', 'wisdom', 'workdocs', 'worklink', 'workmail', 'workmailmessageflow', 'workspaces', 'workspaces-web', 'xray']"; expected "Literal['accessanalyzer']"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Expected output

$ mypy claws.py 
Success: no issues found in 1 source file

Expected behavior

When ServiceName literal has been changed it is updated to each client package.

Or alternatively there is a module where the latest one can be imported directly.

Additionally comparing the ServiceName literals

>>> from mypy_boto3_s3.literals import ServiceName as SN1
>>> from mypy_boto3_secretsmanager.literals import ServiceName as SN2
>>> SN1 == SN2
False
>>> set(SN2.__args__) ^ set(SN1.__args__)
{'gamesparks', 'bedrock', 'bedrock-runtime', 'datazone'}

Additional context

Using Poetry for project / virtualenv management, but that is not relevant.

vemel commented 11 months ago

Thank you for the bug report.

It looks like the only proper solution would be to define your own ServiceName literal with the services you use:

ServiceName = Literal["ec2", "s3", "sns"]

class AWSAccess:
    def __init__(self):
        # Some common setup like logging, access rights, etc here.
        # This is a stripped down version for pointing out boto3-stubs related bug.
        pass

    @staticmethod
    def client(service: ServiceName, **kwargs):
        return boto3.client(service, **kwargs)

    @cached_property
    def s3(self) -> S3Client:
        return self.client("s3")

Or, I can regenerate all packages whenever new services are added or removed.

Let me know what you think.

vemel commented 11 months ago

ServiceName and ResourceServiceName up-to-date literals are now included in mypy-boto3 package:

# pip install mypy-boto3

from mypy_boto3.literals import ServiceName, ResourceServiceName

@jvtm I released mypy-boto3 1.28.83.post1 version with this change. Please let me know if you are satisfied with this solution.

Usage example can be found here: https://pypi.org/project/mypy-boto3/