Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[info] Example automatically generated #826

Closed
rix0rrr opened this issue Sep 27, 2019 · 15 comments
Closed

[info] Example automatically generated #826

rix0rrr opened this issue Sep 27, 2019 · 15 comments
Labels
bug This issue is a bug. language/python Related to Python bindings p1

Comments

@rix0rrr
Copy link
Contributor

rix0rrr commented Sep 27, 2019

In order to provide CDK users with code samples in every language, we automatically translate snippets of TypeScript sample code into other languages.

You can recognize these translated example blocks by them starting with a text similar to the following:

# Example automatically generated. See https://...

This translation is currently experimental, and we'd like you to let us know how this is working out for you. Please comment on this issue if there's something you would like to discuss.

Examples we couldn't compile

We try compiling all the samples before translating them. This is necessary to extract type information that is necessary to render the correct translation of non-TypeScript languages.

However, compilation of sample code requires some setup that we haven't been able to do for all of our code samples yet. That means that many samples are translated without complete type information, and may hence be incorrect. You can recognize them by starting with a comment similar to:

# Example automatically generated without compilation. See https://...

If you encounter issues with some of these samples that are caused by its lack of compilation, we'd love it if you could help out by submitting a Pull Request to make the samples compile! See the following section to figure out what to expect.

Translation mistakes in uncompiled samples

The most common mistake in uncompiled samples is going to be around Structs, which are pure data objects passed to constructors and methods. They are typically called something like FooProps or FooOptions, and in samples they appear something like this:

new SomeClass('param', {
  prop1: 'value1',
  prop2: 'value2'
})

MISTAKE 1: is it a struct or a map?

Mistake 1 the translator may make in translating the preceding code example without having any type information available, is that it can't know whether the argument to new SomeClass is intended to be of type {[key: string]: string} (i.e., a map of string to string), or of type interface SomeClassProps (i.e., a struct).

The caller side for both types looks exactly the same in TypeScript, so the translator can't distinguish between them, and so it is forced to guess.

In most cases uses like this will be structs, so that's what the translator will guess given no other information. However, some classes legitimately take a map as argument (for example, GenericLinuxImage takes a map of region-to-ami), and in those cases the translator will have guessed wrong and produce an incorrect translation.

N.B.: The Java translator will prefer to guess that an untyped value is a map, rather than a struct.

MISTAKE 2: what is the struct's name?

When the translator guesses that something is a struct, it needs to translate it. In a language like Python, structs get translated into keyword arguments and so they don't need names. In other languages like Java and C#, structs get translated into data classes, and you need their name to instantiate them. Unfortunately, the name of the structs doesn't appear in the code sample and since we have no type information we can't look it up.

In those cases, the translator will generate a placeholder name called Struct, with the understanding that you will need to go and look up the actual name when using this code. For example, the C# translator will have translated the above snippet into:

new SomeClass('param', new Struct {
    Prop1 = "value1",
    Prop2 = "value2"
})

You will need to go and look at the documentation of SomeClass to figure out that new Struct actually needs to be new SomeClassProps, or something to that effect.

How to make samples compile successfully

We'd rather have all samples compile successfully. To achieve that, modules need some boilerplate added to make it possible to compile the examples. Typically, this boilerplate file will just import some names or set up some variables. This is called a fixture.

For example, making our running example compilable would look something like this.

Add a file to the package called rosetta/my-fixture.ts-fixture, and put the following into it:

import { SomeClass } from 'my-library';
/// here

And update the example to look like this:

```ts fixture=my-fixture
new SomeClass('param', {
  prop1: 'value1',
  prop2: 'value2'
})
```

The example code will be inserted into the fixture file at the location marked by /// here, and the resulting complete file should compile.

For more information, see the "Examples" section of aws-cdk's Contribution Guide or the "Fixtures" section of the rosetta tool.

Known Issues

The following are known issues with the translation tool:

Language keywords are not respected: Sometimes TypeScript code uses identifiers which are reserved keywords in other languages. The translated code may copy those identifiers without modification, leading to code that won't compile (example: import aws_cdk.aws_lambda as lambda won't actually work in Python as lambda is a reserved keyword).

Single values are interpreted as code snippets: The @example doc comment directive is used both for code snippets, as well as exemplar values for properties. The translator tries to translate the sample values, which will maul them (example).

@rix0rrr rix0rrr added language/python Related to Python bindings investigating This issue is being investigated and/or work is in progress to resolve the issue. labels Sep 27, 2019
@rix0rrr rix0rrr pinned this issue Sep 27, 2019
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Sep 27, 2019

The initial PR is here: #827

@brainstorm
Copy link

brainstorm commented Oct 24, 2019

How is this effort going? My team would absolutely love working python examples on the docs. For now we are relying on the excellent aws-cdk-examples for python, but it would be nice to have working examples inlined in the docs:

Skärmavbild 2019-10-24 kl  18 18 11

I found the issue above under the FileAssetLocation for python :-S

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Nov 20, 2019

Good catch, that needs to be sorted as well.

@SomayaB SomayaB added in-progress Issue is being actively worked on. feature-request A feature should be added or improved. effort/large Large work item – several weeks of effort and removed investigating This issue is being investigated and/or work is in progress to resolve the issue. labels Nov 25, 2019
@curzona
Copy link

curzona commented Dec 6, 2019

lambda is a keyword in python and can't use used as an import alias.

import aws_cdk.aws_lambda as lambda

Ex: https://pypi.org/project/aws-cdk.aws-lambda/

should be

import aws_cdk.aws_lambda as lambda_

Like the aws-sdk-examples do. Ex: https://github.com/aws-samples/aws-cdk-examples/blob/master/python/lambda-cron/app.py

@drissamri
Copy link

drissamri commented Aug 2, 2020

The Java examples seem to have a lot of issues as well with Classes/Builders and imports: https://docs.aws.amazon.com/cdk/api/latest/java/index.html?software/amazon/awscdk/services/dynamodb/package-summary.html

 Table table = new Table(this, "Table", new TableProps()
         .partitionKey(new Attribute().name("id").type(dynamodb.AttributeType.getSTRING())));

should be

    Table table = new Table(this, "Table", TableProps.builder()
                .partitionKey(Attribute.builder()
                        .name("id")
                        .type(AttributeType.STRING)
                        .build())
                .build());

@WhyNotHugo
Copy link

Static methods should not have self as a first parameter:

arn = "arn:aws:..."
certificate = Certificate.from_certificate_arn(self, "Certificate", arn)

https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_certificatemanager/README.html#importing

@rix0rrr rix0rrr assigned RomainMuller and unassigned rix0rrr Jun 4, 2021
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Jun 4, 2021

Sorry to do this to your @RomainMuller but since you're working on Rosetta right now anyway, might as well work in these bug reports at the same time? 😇

@rix0rrr rix0rrr added bug This issue is a bug. and removed feature-request A feature should be added or improved. effort/large Large work item – several weeks of effort in-progress Issue is being actively worked on. labels Jun 4, 2021
@RomainMuller RomainMuller removed their assignment Jun 24, 2021
@ryparker
Copy link
Contributor

ryparker commented Jun 24, 2021

Leaving a note here that I recently came across an issue which involved a python example that does not compile and can lead to some confusion.

Example

# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
from aws_cdk.core import CustomResource
import aws_cdk.aws_logs as logs
import aws_cdk.aws_iam as iam
import aws_cdk.custom_resources as cr

on_event = lambda_.Function(self, "MyHandler")

my_role = iam.Role(self, "MyRole")

my_provider = cr.Provider(self, "MyProvider",
    on_event_handler=on_event,
    is_complete_handler=is_complete, # optional async "waiter"
    log_retention=logs.RetentionDays.ONE_DAY, # default is INFINITE
    role=my_role
)

CustomResource(self, "Resource1", service_token=my_provider.service_token)
CustomResource(self, "Resource2", service_token=my_provider.service_token)

This example requires some modifications in order to compile. Here's is a modified version of the above example that works. (Given the 2 lambda handlers are provided in external files)

from aws_cdk import core as cdk
import aws_cdk.aws_lambda as lambda_
import aws_cdk.aws_logs as logs
import aws_cdk.aws_iam as iam
import aws_cdk.custom_resources as cr

class FooStack(cdk.Construct):
    def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        with open("src/lambda_handlers/on_event.py", encoding="utf-8") as fp:
            on_event_code_body = fp.read()

        on_event = lambda_.Function(self, "on_event",
            runtime=lambda_.Runtime.PYTHON_3_7,
            handler="index.on_event",
            code=lambda_.InlineCode(on_event_code_body),
        )

        with open("src/lambda_handlers/is_complete.py", encoding="utf-8") as fp:
            is_complete_code_body = fp.read()

        is_complete = lambda_.Function(self, "is_complete",
            runtime=lambda_.Runtime.PYTHON_3_7,
            handler="index.is_complete",
            code=lambda_.InlineCode(is_complete_code_body),
        )

        my_role = iam.Role(self, "MyRole",
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com")
        )

        my_provider = cr.Provider(self, "MyProvider",
            on_event_handler=on_event,
            is_complete_handler=is_complete, # optional async "waiter"
            log_retention=logs.RetentionDays.ONE_DAY, # default is INFINITE
            role=my_role
        )

        cdk.CustomResource(self, "Resource1", service_token=my_provider.service_token)
        cdk.CustomResource(self, "Resource2", service_token=my_provider.service_token)

@bl-ue
Copy link

bl-ue commented Jul 12, 2021

Bug with Python translation of JavaScript instanceof keyword (aws-cdk/aws-s3, https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_s3/README.html#encryption):

assert(bucket.encryption_key instanceof kms.Key)

Python doesn't have the instanceof keyword. The correct form is:

assert(isinstance(bucket.encryption_key, kms.Key))

@bl-ue
Copy link

bl-ue commented Jul 12, 2021

Bug with Python translation of JavaScript ?? (nullish-coalescing operator) (aws-cdk/core, https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.core/README.html)

uniqueid = "GloballyUniqueIdForSingleton"return stack.node.try_find_child(uniqueid) ?? sns.Topic(stack, uniqueid)

It should be

uniqueid = "GloballyUniqueIdForSingleton"
return stack.node.try_find_child(uniqueid) or sns.Topic(stack, uniqueid)

(Also, there's a missing newline between the string literal and the return keyword 🤔)

@tvb
Copy link

tvb commented Aug 18, 2021

Just noted:

# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
assets.Asset(self, "BundledAsset",
    path="/path/to/asset",
    bundling={
        "local": {
            def try_bundle(self, output_dir, options):
                if can_run_locally: return Truereturn False
        },
        # Docker bundling fallback
        "image": DockerImage.from_registry("alpine"),
        "entrypoint": ["/bin/sh", "-c"],
        "command": ["bundle"]
    }
)
if can_run_locally: return Truereturn False

Looks wrong to me.

mergify bot pushed a commit to aws/aws-cdk that referenced this issue Oct 28, 2021
The examples we copy into docblocks may contain block comments themselves.

However, the docblock renderer does not escape the docblock *closing* text, so the doc block gets terminated early and compiling fails:

```java
/**
 * Initialization props for the `NestedStack` construct.
 * <p>
 * Example:
 * <p>
 * <blockquote><pre>{@code
 * // Example automatically generated. See aws/jsii#826
 * import software.amazon.awscdk.core.App;
 * import software.amazon.awscdk.core.CfnOutput;
 * import software.amazon.awscdk.core.NestedStack;
 * import lib.RestApi;
 * import lib.Stage;
 * /**
 *  * This file showcases how to split up a RestApi's Resources and Methods across nested stacks.
 *  *
 *  * The root stack 'RootStack' first defines a RestApi.
 *  * Two nested stacks BooksStack and PetsStack, create corresponding Resources '/books' and '/pets'.
 *  * They are then deployed to a 'prod' Stage via a third nested stack - DeployStack.
 *  *
 *  * To verify this worked, go to the APIGateway
 *  */    <------------ OOOPS!
 * public class RootStack extends Stack {
 *     public RootStack(Construct scope) {
 *         super(scope, "integ-restapi-import-RootStack");
 *         RestApi restApi = RestApi.Builder.cre

```

Revert this until we can address the quoting issue.

Reverts #17191
@arcrank
Copy link

arcrank commented Nov 3, 2021

Another instance where JSII doesn't play nice with python, in aws-cdk python docs.

product = servicecatalog.CloudFormationProduct(self, "MyFirstProduct",
    product_name="My Product",
    owner="Product Owner",
    product_versions=[{
        "product_version_name": "v1",
        "cloud_formation_template": servicecatalog.CloudFormationTemplate.from_url("https://raw.githubusercontent.com/awslabs/aws-cloudformation-templates/master/aws/services/ServiceCatalog/Product.yaml")
    }, {
        "product_version_name": "v2",
        "cloud_formation_template": servicecatalog.CloudFormationTemplate.from_asset(path.join(__dirname, "development-environment.template.json"))
    }
    ]
)

but when actually running cdk commands the field cloud_formation_template is actually cloudFormationTemplate.
You would get error

jsii.errors.JSIIError: Missing required properties for @aws-cdk/aws-servicecatalog.CloudFormationProductVersion: cloudFormationTemplate

Seems odd to me since most python translations are snake case.

@peterwoodworth peterwoodworth added p1 and removed p2 labels Nov 10, 2021
@peterwoodworth
Copy link
Contributor

Another issue here in the docs

Specifically, FlinkApplicationProperties doesn't work the way the documentation describes here

    property_groups=PropertyGroups(
        FlinkApplicationProperties={
            "input_stream_name": "my-input-kinesis-stream",
            "output_stream_name": "my-output-kinesis-stream"
        }
    )

Mimic this example and you will fail with this error:
__init__() got an unexpected keyword argument 'FlinkApplicationProperties'

More information can be found about this issue in this comment here

@rix0rrr rix0rrr unpinned this issue Dec 17, 2021
TikiTDO pushed a commit to TikiTDO/aws-cdk that referenced this issue Feb 21, 2022
The examples we copy into docblocks may contain block comments themselves.

However, the docblock renderer does not escape the docblock *closing* text, so the doc block gets terminated early and compiling fails:

```java
/**
 * Initialization props for the `NestedStack` construct.
 * <p>
 * Example:
 * <p>
 * <blockquote><pre>{@code
 * // Example automatically generated. See aws/jsii#826
 * import software.amazon.awscdk.core.App;
 * import software.amazon.awscdk.core.CfnOutput;
 * import software.amazon.awscdk.core.NestedStack;
 * import lib.RestApi;
 * import lib.Stage;
 * /**
 *  * This file showcases how to split up a RestApi's Resources and Methods across nested stacks.
 *  *
 *  * The root stack 'RootStack' first defines a RestApi.
 *  * Two nested stacks BooksStack and PetsStack, create corresponding Resources '/books' and '/pets'.
 *  * They are then deployed to a 'prod' Stage via a third nested stack - DeployStack.
 *  *
 *  * To verify this worked, go to the APIGateway
 *  */    <------------ OOOPS!
 * public class RootStack extends Stack {
 *     public RootStack(Construct scope) {
 *         super(scope, "integ-restapi-import-RootStack");
 *         RestApi restApi = RestApi.Builder.cre

```

Revert this until we can address the quoting issue.

Reverts aws#17191
@heitorlessa
Copy link

heitorlessa commented Sep 2, 2022

I've just hit this when trying to use ILocalBundling. I couldn't find the docs so I kept searching for tests in jsii, and the closest I found was closed aws/aws-cdk#17928.

I'd be more than happy to contribute to the docs if I manage to find a solution.

Error: Failed to bundle asset testV39-lambda-layer-afca3bb3-4495-4f22-b8ac-4f345b9b25ec/aws-lambda-powertools-e2e-test/Code/Stage, bundle output is located at /Users/lessa/DEV/aws-lambda-powertools-python/tests/e2e/tracer/cdk.out/asset.f0f2e3bad29d71e35a9ec7740809279d1a3f36af4f1c905b438aacd6fc2bcf12-error:

TypeError: options.local?.tryBundle is not a function

@jsii.implements(ILocalBundling)
class LocalPipInstall:
    @staticmethod
    @jsii.member(jsii_name="tryBundle")
    def try_bundle(output_dir: str, **kwargs) -> bool:
        install_command = f'pip install .\[pydantic\] --platform manylinux1_x86_64 --only-binary=:all: -t {output_dir}'
        subprocess.run(install_command, shell=True)
        return True
  
    # try this too to no avail. Omitting staticmethod returns a Callable signature error
    @staticmethod
    @jsii.member(jsii_name="tryBundle")
    def tryBundle(output_dir: str, **kwargs) -> bool:
        install_command = f'pip install .\[pydantic\] --platform manylinux1_x86_64 --only-binary=:all: -t {output_dir}'
        subprocess.run(install_command, shell=True)
        return True


....
            code=Code.from_asset(
                path=str(SOURCE_CODE_ROOT_PATH),
                bundling=BundlingOptions(
                    image=DockerImage.from_build(
                        str(Path(__file__).parent),
                        build_args={"IMAGE": PythonVersion[PYTHON_RUNTIME_VERSION].value["image"]},
                    ),
                    command=["bash", "-c", " && ".join(build_commands)],

					# Here
                    local=LocalPipInstall(),


                ),
            ),

@mrgrain mrgrain closed this as not planned Won't fix, can't repro, duplicate, stale Apr 18, 2024
Copy link
Contributor

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. language/python Related to Python bindings p1
Projects
None yet
Development

No branches or pull requests