From 997dbcc33fa6802ae807db07a392a7382df7dc7c Mon Sep 17 00:00:00 2001 From: Mitch Garnaat Date: Tue, 2 Apr 2019 08:32:10 -0700 Subject: [PATCH] feat: Add python support to cdk init (#2130) * First take on an init template for a Python CDK project. * The cdk.context.json should not be ignored. * Fixing some review issues * Restructured to move app into a separate file outside of package directory. Also some formatting changes. * Slight change to code formatting. * Remove reference to app.sh * Moving this over to sample-app since it actually creates a sample app, not an empty project. Will need to create a separate issue to move the others over and create templates for empty projects. * Adding an app template for Python. * Keep all dependencies in setup.py and use -e . in requirements.txt to use those and automatically run the python setup.py develop step. Also use templating feature for blank app. * Templatize the class name. --- .../python/%name%/%name%_stack.template.py | 9 ++++ .../app/python/%name%/__init__.py | 0 .../lib/init-templates/app/python/.gitignore | 6 +++ .../lib/init-templates/app/python/README.md | 37 ++++++++++++++ .../init-templates/app/python/app.template.py | 11 +++++ .../lib/init-templates/app/python/cdk.json | 3 ++ .../app/python/requirements.txt | 1 + .../app/python/setup.template.py | 45 +++++++++++++++++ .../sample-app/python/.gitignore | 6 +++ .../sample-app/python/README.md | 44 +++++++++++++++++ .../init-templates/sample-app/python/app.py | 12 +++++ .../init-templates/sample-app/python/cdk.json | 3 ++ .../sample-app/python/hello/__init__.py | 0 .../python/hello/hello_construct.py | 22 +++++++++ .../sample-app/python/hello/hello_stack.py | 30 ++++++++++++ .../sample-app/python/requirements.txt | 2 + .../init-templates/sample-app/python/setup.py | 49 +++++++++++++++++++ .../sample-app/python/tests/__init__.py | 0 .../sample-app/python/tests/unit/__init__.py | 0 .../python/tests/unit/test_hello_construct.py | 16 ++++++ packages/aws-cdk/lib/init.ts | 16 ++++++ 21 files changed, 312 insertions(+) create mode 100644 packages/aws-cdk/lib/init-templates/app/python/%name%/%name%_stack.template.py create mode 100644 packages/aws-cdk/lib/init-templates/app/python/%name%/__init__.py create mode 100644 packages/aws-cdk/lib/init-templates/app/python/.gitignore create mode 100644 packages/aws-cdk/lib/init-templates/app/python/README.md create mode 100644 packages/aws-cdk/lib/init-templates/app/python/app.template.py create mode 100644 packages/aws-cdk/lib/init-templates/app/python/cdk.json create mode 100644 packages/aws-cdk/lib/init-templates/app/python/requirements.txt create mode 100644 packages/aws-cdk/lib/init-templates/app/python/setup.template.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/.gitignore create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/README.md create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/app.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/cdk.json create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/hello/__init__.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_construct.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_stack.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/requirements.txt create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/setup.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/tests/__init__.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/__init__.py create mode 100644 packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/test_hello_construct.py diff --git a/packages/aws-cdk/lib/init-templates/app/python/%name%/%name%_stack.template.py b/packages/aws-cdk/lib/init-templates/app/python/%name%/%name%_stack.template.py new file mode 100644 index 0000000000000..46f1808e14701 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/%name%/%name%_stack.template.py @@ -0,0 +1,9 @@ +from aws_cdk import cdk + + +class %name.PascalCased%Stack(cdk.Stack): + + def __init__(self, app: cdk.App, id: str, **kwargs) -> None: + super().__init__(app, id) + + # The code that defines your stack goes here diff --git a/packages/aws-cdk/lib/init-templates/app/python/%name%/__init__.py b/packages/aws-cdk/lib/init-templates/app/python/%name%/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/app/python/.gitignore b/packages/aws-cdk/lib/init-templates/app/python/.gitignore new file mode 100644 index 0000000000000..180c9bf9bab9c --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/.gitignore @@ -0,0 +1,6 @@ +*.swp +package-lock.json +__pycache__ +.pytest_cache +.env +*.egg-info diff --git a/packages/aws-cdk/lib/init-templates/app/python/README.md b/packages/aws-cdk/lib/init-templates/app/python/README.md new file mode 100644 index 0000000000000..462a108c4e1d9 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/README.md @@ -0,0 +1,37 @@ + +# Welcome to your CDK Python project! + +This is a blank project for Python development with CDK. + +The `cdk.json` file tells the CDK Toolkit how to execute your app. + +This project is set up like a standard Python project. The initialization process also creates +a virtualenv within this project, stored under the .env directory. + +After the init process completes, you can use the following steps to get your project set up. + +``` +$ source .env/bin/activate +$ pip install -r requirements.txt +$ python setup.py develop +``` + +At this point you can now synthesize the CloudFormation template for this code. + +``` +$ cdk synth +``` + +To add additional dependencies, for example other CDK libraries, just add to +your requirements.txt file and rerun the `pip install -r requirements.txt` +command. + +# Useful commands + + * `cdk ls` list all stacks in the app + * `cdk synth` emits the synthesized CloudFormation template + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk docs` open CDK documentation + +Enjoy! diff --git a/packages/aws-cdk/lib/init-templates/app/python/app.template.py b/packages/aws-cdk/lib/init-templates/app/python/app.template.py new file mode 100644 index 0000000000000..0a194f9bd131b --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/app.template.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +from aws_cdk import cdk + +from %name%.%name%_stack import PyStack + + +app = cdk.App() +PyStack(app, "%name%-cdk-1") + +app.run() diff --git a/packages/aws-cdk/lib/init-templates/app/python/cdk.json b/packages/aws-cdk/lib/init-templates/app/python/cdk.json new file mode 100644 index 0000000000000..787a71dd6e881 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/packages/aws-cdk/lib/init-templates/app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/app/python/requirements.txt new file mode 100644 index 0000000000000..d6e1198b1ab1f --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/requirements.txt @@ -0,0 +1 @@ +-e . diff --git a/packages/aws-cdk/lib/init-templates/app/python/setup.template.py b/packages/aws-cdk/lib/init-templates/app/python/setup.template.py new file mode 100644 index 0000000000000..0c0c8dc267231 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/app/python/setup.template.py @@ -0,0 +1,45 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="%name%", + version="0.0.1", + + description="An empty CDK Python app", + long_description=long_description, + long_description_content_type="text/markdown", + + author="author", + + package_dir={"": "%name%"}, + packages=setuptools.find_packages(where="%name%"), + + install_requires=[ + "aws-cdk.cdk", + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/.gitignore b/packages/aws-cdk/lib/init-templates/sample-app/python/.gitignore new file mode 100644 index 0000000000000..180c9bf9bab9c --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/.gitignore @@ -0,0 +1,6 @@ +*.swp +package-lock.json +__pycache__ +.pytest_cache +.env +*.egg-info diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/README.md b/packages/aws-cdk/lib/init-templates/sample-app/python/README.md new file mode 100644 index 0000000000000..a475424f8bbff --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/README.md @@ -0,0 +1,44 @@ + +# Welcome to your CDK Python project! + +You should explore the contents of this template. It demonstrates a CDK app with two instances of +a stack (`HelloStack`) which also uses a user-defined construct (`HelloConstruct`). + +The `cdk.json` file tells the CDK Toolkit how to execute your app. + +This project is set up like a standard Python project. The initialization process also creates +a virtualenv within this project, stored under the .env directory. + +After the init process completes, you can use the following steps to get your project set up. + +``` +$ source .env/bin/activate +$ pip install -r requirements.txt +``` + +At this point you can now synthesize the CloudFormation template for this code. + +``` +$ cdk synth +``` + +You can now begin exploring the source code, contained in the hello directory. +There is also a very trivial test included that can be run like this: + +``` +$ pytest +``` + +To add additional dependencies, for example other CDK libraries, just add to +your requirements.txt file and rerun the `pip install -r requirements.txt` +command. + +# Useful commands + + * `cdk ls` list all stacks in the app + * `cdk synth` emits the synthesized CloudFormation template + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk docs` open CDK documentation + +Enjoy! diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/app.py b/packages/aws-cdk/lib/init-templates/sample-app/python/app.py new file mode 100644 index 0000000000000..1754ff4ab6f1b --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/app.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +from aws_cdk import cdk + +from hello.hello_stack import MyStack + + +app = cdk.App() +MyStack(app, "hello-cdk-1", env={'region': 'us-east-2'}) +MyStack(app, "hello-cdk-2", env={'region': 'us-west-2'}) + +app.run() diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/cdk.json b/packages/aws-cdk/lib/init-templates/sample-app/python/cdk.json new file mode 100644 index 0000000000000..787a71dd6e881 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/hello/__init__.py b/packages/aws-cdk/lib/init-templates/sample-app/python/hello/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_construct.py b/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_construct.py new file mode 100644 index 0000000000000..d9637d43d82a5 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_construct.py @@ -0,0 +1,22 @@ +from aws_cdk import ( + aws_iam as iam, + aws_s3 as s3, + cdk, +) + + +class HelloConstruct(cdk.Construct): + + @property + def buckets(self): + return tuple(self._buckets) + + def __init__(self, scope: cdk.Construct, id: str, num_buckets: int) -> None: + super().__init__(scope, id) + self._buckets = [] + for i in range(0, num_buckets): + self._buckets.append(s3.Bucket(self, f"Bucket-{i}")) + + def grant_read(self, principal: iam.IPrincipal): + for b in self.buckets: + b.grant_read(principal, "*") diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_stack.py b/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_stack.py new file mode 100644 index 0000000000000..0efa1aa145d04 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/hello/hello_stack.py @@ -0,0 +1,30 @@ +from aws_cdk import ( + aws_iam as iam, + aws_sqs as sqs, + aws_sns as sns, + cdk +) + +from hello_construct import HelloConstruct + + +class MyStack(cdk.Stack): + + def __init__(self, app: cdk.App, id: str, **kwargs) -> None: + super().__init__(app, id, **kwargs) + + queue = sqs.Queue( + self, "MyFirstQueue", + visibility_timeout_sec=300, + ) + + topic = sns.Topic( + self, "MyFirstTopic", + display_name="My First Topic" + ) + + topic.subscribe_queue(queue) + + hello = HelloConstruct(self, "MyHelloConstruct", num_buckets=4) + user = iam.User(self, "MyUser") + hello.grant_read(user) diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/requirements.txt b/packages/aws-cdk/lib/init-templates/sample-app/python/requirements.txt new file mode 100644 index 0000000000000..ae60ed5f14ca8 --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/requirements.txt @@ -0,0 +1,2 @@ +-e . +pytest diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/setup.py b/packages/aws-cdk/lib/init-templates/sample-app/python/setup.py new file mode 100644 index 0000000000000..c44c585d2d90c --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/setup.py @@ -0,0 +1,49 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="hello", + version="0.0.1", + + description="A sample CDK Python app", + long_description=long_description, + long_description_content_type="text/markdown", + + author="author", + + package_dir={"": "hello"}, + packages=setuptools.find_packages(where="hello"), + + install_requires=[ + "aws-cdk.cdk", + "aws-cdk.aws_iam", + "aws-cdk.aws_sqs", + "aws-cdk.aws_sns", + "aws-cdk.aws_s3", + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/tests/__init__.py b/packages/aws-cdk/lib/init-templates/sample-app/python/tests/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/__init__.py b/packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/test_hello_construct.py b/packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/test_hello_construct.py new file mode 100644 index 0000000000000..4af1107c5e83b --- /dev/null +++ b/packages/aws-cdk/lib/init-templates/sample-app/python/tests/unit/test_hello_construct.py @@ -0,0 +1,16 @@ +import unittest + +from aws_cdk import cdk + +from hello.hello_construct import HelloConstruct + +class TestHelloConstruct(unittest.TestCase): + + def setUp(self): + self.app = cdk.App() + self.stack = cdk.Stack(self.app, "TestStack") + + def test_num_buckets(self): + num_buckets = 10 + hello = HelloConstruct(self.stack, "Test1", num_buckets) + assert len(hello.buckets) == num_buckets \ No newline at end of file diff --git a/packages/aws-cdk/lib/init.ts b/packages/aws-cdk/lib/init.ts index f0475873c3691..c869ee55eaa3e 100644 --- a/packages/aws-cdk/lib/init.ts +++ b/packages/aws-cdk/lib/init.ts @@ -231,6 +231,8 @@ async function postInstall(language: string, canUseNetwork: boolean) { return await postInstallTypescript(canUseNetwork); case 'java': return await postInstallJava(canUseNetwork); + case 'python': + return await postInstallPython(canUseNetwork); } } @@ -260,6 +262,20 @@ async function postInstallJava(canUseNetwork: boolean) { await execute('mvn', 'package'); } +async function postInstallPython(canUseNetwork: boolean) { + if (!canUseNetwork) { + print(`Please run ${colors.green('python -m venv .env')}!`); + return; + } + + print(`Executing ${colors.green('python -m venv .env')}`); + try { + await execute('python3', '-m venv', '.env'); + } catch (e) { + throw new Error(`${colors.green('python3 -m venv .env')} failed: ` + e.message); + } +} + /** * @param dir a directory to be checked * @returns true if ``dir`` is within a git repository.