aws / jsii

jsii allows code in any language to naturally interact with JavaScript classes. It is the technology that enables the AWS Cloud Development Kit to deliver polyglot libraries from a single codebase!
https://aws.github.io/jsii
Apache License 2.0
2.59k stars 242 forks source link

Python code failing type checking #4531

Open rix0rrr opened 3 weeks ago

rix0rrr commented 3 weeks ago

Reported in another issue

@dmartin-gh

I am also experiencing the interface issues described above. We're looking to adopt the CDK for our main platform and as a mostly Python/C++ shop the Python CDK seemed like a great choice for us. I didn't make it very far into my first sample app to test things out before mypy started throwing errors.

from aws_cdk.core import Construct, Stack
from aws_cdk import aws_ec2 as ec2

class MyEC2Stack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ec2.Instance(self, 'my-app',
            instance_type=ec2.InstanceType('m5.4xlarge'),
            machine_image=ec2.MachineImage.generic_linux({
                'us-east-1': 'ami-0affd4508a5d2481b', # CentOS 7 (x86_64) - with Updates HVM
            }),
            vpc=ec2.Vpc(self, "my-app-vpc"))

image I would love to see this fixed so we can start building out our application stack with confidence that we're passing the right level of constructs around!

Is this still a problem today? I have been trying to reproduce this (with CDK v2, though), and am not getting the MyPy error you report here... if you still happen to have the error, maybe this is because of your specific MyMy version or configuration (in which case, I would like to know what these are so I can reproduce).

Indeed it is still a problem. For example try loading up apigw-http-api-lambda-dynamodb-python-cdk in vscode, then pyright reports for

        # Create the Lambda function to receive the request
        api_hanlder = lambda_.Function(
            ...
        )

        ...

        # Create API Gateway
        apigw_.LambdaRestApi(
           ...
            handler=api_hanlder,  # Pyright error: Argument of type "Function" cannot be assigned to parameter "handler" of type "IFunction"
        )

typecheck error

Argument of type "Function" cannot be assigned to parameter "handler" of type "IFunction" in function "__init__"
  "Function" is incompatible with protocol "IFunction"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"
    "IFunction" is incompatible with "Function"Pylance[reportArgumentType](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportArgumentType)
(variable) api_hanlder: Function

as shown in this screenshot

image

That project uses aws-cdk-lib==2.77.0 however the same issue exists after updating to recent aws-cdk-lib==2.143.1. On my machine it happens with the following configuration

pyright 1.1.364
pylance 2024.5.103
aws-cdk-lib 2.143.1
python 3.11.2
vscode 1.89.1

Originally posted by @mariogalic in https://github.com/aws/jsii/issues/1919#issuecomment-2142047331

polothy commented 3 weeks ago

Also related to this issue:

I'm also still seeing this issue (https://github.com/aws/jsii/issues/2877) in a JetBrains IDE (Intellij IDEA Ultimate with Python plugin). A comment in the issue near the end says it's fixed, but I see the same Expected type 'str | str | None', got '() -> str | str' instead error in my IDE today using CDK v2.144.0.

These two typing issues combined make Python experience really rough because your IDE thinks you have a lot of invalid types and sometimes its hard to see which typing issue is an actual problem unless you run cdk synth/deploy.

mikewrighton commented 3 weeks ago

I took a look at apigw-http-api-lambda-dynamodb-python-cdk and was able to root cause at least one issue causing these type checker errors.

When you implement an interface in TS, the method names have to match, but the method argument names do not, as long as the argument types are in the correct order. In Python however, when you implement a Protocol (which is how we do interfaces), the method argument names do have to match. So when our TS library has things like IPrincipal.addToPrincipalPolicy(statement: PolicyStatement) and an implementation of PrincipalBase.addToPrincipalPolicy(_statement: PolicyStatement) the former generates an IPrincipal Protocol in python, and the latter generates a class that's incompatible, and we get the PyRight error:

...
        "AnyPrincipal" is incompatible with protocol "IPrincipal"
          "IPrincipal" is incompatible with "AnyPrincipal"
          "IPrincipal" is incompatible with "AnyPrincipal"
          "IPrincipal" is incompatible with "AnyPrincipal"
          "add_to_principal_policy" is an incompatible type

The suggested fix here is to always use the method argument names in the base (Protocol) class, when generating subclasses. In the example above, PrincipalBase.addToPrincipalPolicy() would use the method argument statement instead of what's in the TS code, _statement. I didn't get as far as implementation but hopefully this context is useful.

adriandelgg commented 2 days ago

I have this issue too in Intellij IDEA Ultimate w/ Python. Super annoying. I don't get the error in VS Code.