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
515 stars 35 forks source link

Output types broken as input types InventoryConfigurationOutputTypeDef, LifecycleRuleOutputTypeDef #254

Open sodul opened 2 months ago

sodul commented 2 months ago

Describe the bug After upgrading to 1.34.92 (confirmed with 1.34.93) our codebase is getting 2 new mypy errors with:

To Reproduce Steps to reproduce the behavior: Add code that works with the output as input. InventoryConfigurationOutputTypeDef, LifecycleRuleOutputTypeDef

  1. Install boto3-stubs[s3]
  2. Run mypy/pyright on the following code sample
from typing import TYPE_CHECKING
import boto3
if TYPE_CHECKING:
    from mypy_boto3_s3 import S3Client
    from mypy_boto3_s3.type_defs import LifecycleRuleOutputTypeDef
    from mypy_boto3_s3.type_defs import LifecycleRuleTypeDef

client: S3Client = boto3.client('s3')
rules = client.get_bucket_lifecycle_configuration(Bucket='bucket_name')['Rules']
new_rule: LifecycleRuleTypeDef = {
    'ID': 'rule_name',
    'Expiration': {'Days': 1},
    'Filter': {'Prefix': 'prefix'},
    'NoncurrentVersionExpiration': {'NoncurrentDays': 1},
    'AbortIncompleteMultipartUpload': {'DaysAfterInitiation': 1},
    'Status': 'Enabled',
}
rules.append(new_rule)

Actual output

> mypy s3.py
s3.py:18: error: Argument 1 to "append" of "list" has incompatible type "LifecycleRuleTypeDef"; expected "LifecycleRuleOutputTypeDef"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Expected output

no error

Additional context Your OS macOS and linux, boto3-stubs installation method, boto3 version, etc.

Relates to #208

vemel commented 2 months ago

Hello! THank you for the report.

Looks like this output type is not compatible with the corresponding input type. I will take a look.

vemel commented 2 months ago

Unfortunately, these types are incompatible. Does rewriting code as

new_rule: LifecycleRuleOutputTypeDef = {
    'ID': 'rule_name',
    'Expiration': {'Days': 1},
    'Filter': {'Prefix': 'prefix'},
    'NoncurrentVersionExpiration': {'NoncurrentDays': 1},
    'AbortIncompleteMultipartUpload': {'DaysAfterInitiation': 1},
    'Status': 'Enabled',
}

work for you?

sodul commented 2 months ago

It does not seem to help. We are going to use # type: ignore for now:

rules: list[LifecycleRuleTypeDef]
rules = client.get_bucket_lifecycle_configuration( # type: ignore[assignment]
    Bucket='bucket_name'
)['Rules']

Not in the example above but the next line we have is:

config: BucketLifecycleConfigurationTypeDef = {'Rules': rules}

And mypy was failing with this error:

Incompatible types (expression has type "list[LifecycleRuleOutputTypeDef]", TypedDict item "Rules" has type "Sequence[LifecycleRuleTypeDef]")  [typeddict-item] (1,955:64)
vemel commented 2 months ago

As far as I understand, before you used mypy-boto3-s3 1.34.65. There was a bug fixed in #244 that incompatible output shapes were used instead of separating output and input shapes in case of conflict.

For this particular shape input and output definitions are not compatible. So, type: ignore looks like the easiest solution.

pyright changes the way it compares TypedDicts in https://github.com/microsoft/pyright/releases/tag/1.1.333 release. So, since TypedDicts are invariant, output TypedDict cannot be assigned to an input TypedDict.

I will cross-check again tomorrow.