Skip to content

Commit

Permalink
feat: Add python support to cdk init (#2130)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
garnaat authored Apr 2, 2019
1 parent 2e92d44 commit 997dbcc
Show file tree
Hide file tree
Showing 21 changed files with 312 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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
Empty file.
6 changes: 6 additions & 0 deletions packages/aws-cdk/lib/init-templates/app/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.swp
package-lock.json
__pycache__
.pytest_cache
.env
*.egg-info
37 changes: 37 additions & 0 deletions packages/aws-cdk/lib/init-templates/app/python/README.md
Original file line number Diff line number Diff line change
@@ -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!
11 changes: 11 additions & 0 deletions packages/aws-cdk/lib/init-templates/app/python/app.template.py
Original file line number Diff line number Diff line change
@@ -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()
3 changes: 3 additions & 0 deletions packages/aws-cdk/lib/init-templates/app/python/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "python3 app.py"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .
45 changes: 45 additions & 0 deletions packages/aws-cdk/lib/init-templates/app/python/setup.template.py
Original file line number Diff line number Diff line change
@@ -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",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.swp
package-lock.json
__pycache__
.pytest_cache
.env
*.egg-info
44 changes: 44 additions & 0 deletions packages/aws-cdk/lib/init-templates/sample-app/python/README.md
Original file line number Diff line number Diff line change
@@ -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!
12 changes: 12 additions & 0 deletions packages/aws-cdk/lib/init-templates/sample-app/python/app.py
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "python3 app.py"
}
Empty file.
Original file line number Diff line number Diff line change
@@ -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, "*")
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-e .
pytest
49 changes: 49 additions & 0 deletions packages/aws-cdk/lib/init-templates/sample-app/python/setup.py
Original file line number Diff line number Diff line change
@@ -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",
],
)
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions packages/aws-cdk/lib/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 997dbcc

Please sign in to comment.