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

feat: Add python support to cdk init #2130

Merged
merged 11 commits into from
Apr 2, 2019

Conversation

garnaat
Copy link
Contributor

@garnaat garnaat commented Apr 1, 2019

Introduces an init template for Python projects, thus enabling cdk init --language python.

There are (at least) two potentially controversial approaches to this template.

  • The template creates a virtualenv in the directory and provides instructions for how to use it. There is currently no way to disable this behavior. I feel that the vast majority of use cases would benefit from a virtualenv but it could complicate some other use cases. Of course, you could always just delete the virtualenv or ignore it.
  • The template assumes you want to build a Python package. So, there is a setup.py and the README instructs the user to run python setup.py develop to build the package in a way to makes it easy to develop locally. I think this better aligns with where a developer would eventually want to go but does so at the expense of more initial complexity.

Pull Request Checklist

  • Testing
    • Unit test added (prefer not to modify an existing test, otherwise, it's probably a breaking change)
    • CLI change?: coordinate update of integration tests with team
    • cdk-init template change?: coordinated update of integration tests with team
  • Docs
    • jsdocs: All public APIs documented
    • README: README and/or documentation topic updated
  • Title and Description
    • Change type: title prefixed with fix, feat will appear in changelog
    • Title: use lower-case and doesn't end with a period
    • Breaking?: last paragraph: "BREAKING CHANGE: <describe what changed + link for details>"
    • Issues: Indicate issues fixed via: "Fixes #xxx" or "Closes #xxx"
  • Sensitive Modules (requires 2 PR approvers)
    • IAM Policy Document (in @aws-cdk/aws-iam)
    • EC2 Security Groups and ACLs (in @aws-cdk/aws-ec2)
    • Grant APIs (only if not based on official documentation with a reference)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

@garnaat garnaat requested a review from a team as a code owner April 1, 2019 13:09
@garnaat garnaat requested a review from dstufft April 1, 2019 13:09
Copy link
Contributor

@RomainMuller RomainMuller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me overall, but I'm not enough of a Python practitioner to have an opinion on the "possibly controversial" decisions here... I'll defer that to people with more experience on the subject, who can understand the tradeoffs & such.

packages/aws-cdk/lib/init-templates/app/python/.gitignore Outdated Show resolved Hide resolved
@@ -0,0 +1,42 @@

Welcome to your CDK Python project!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template should actually be called "sample-app". The "app" template should result in an empty stack (so you don't have to go delete things). See typescript as an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by this comment. I was following the existing examples for csharp, java, etc. Is this inconsistent with them?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well.... those should be changed to ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Yeah, its kind of backwards now. Do you want to fix all of them now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So do you want to change all of those now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's start by renaming this specific template to sample-app and then follow up with a PR for an empty app in python.

packages/aws-cdk/lib/init-templates/app/python/README.md Outdated Show resolved Hide resolved
packages/aws-cdk/lib/init-templates/app/python/README.md Outdated Show resolved Hide resolved
package_dir={"": "hello"},
packages=setuptools.find_packages(where="hello"),

install_requires=[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense in python-land to have this duplicated with requirements.txt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many packages use both but I have simplified this to put the requirements in the setup.py and then tell pip to use those rather than list them explicitly in requirements.txt.


print(`Executing ${colors.green('python -m venv .env')}`);
try {
await execute('python3', '-m venv', '.env');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to also do the pip install stuff here so people can get started quicker?

```
$ source .env/bin/activate
$ pip install -r requirements.txt
$ python setup.py develop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't develop for libraries (as opposed to apps)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop is just a variant of install that allows you to edit your code and run it without having to re-install. This example really consists of both an app and a library. I have restructured the code slightly to make that more clear, I hope.

@@ -0,0 +1,3 @@
{
"app": "python3 hello/hello_stack.py"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this include running via the venv? Isn't that a better experience than requiring users to have pre-actived their shell and THEN running cdk synth?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a good idea. We should be able to just point to the python3 executable in the virtualenv.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EXE on Windows (for 3.7 at least as I just installed it last week) is just python.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets ugly. If we are using a virtualenv that has been created using Python3 then there is no real need to say python3 here. However, that does mean that during the init process we have done a python3 -m venv .env so this, too, will fail on Windows.

We could try python3 for the virtualenv and then try python if that fails but this would cause problems on a machine that does not have Python3 installed at all because we would end up with a virtualenv for Python2.

Maybe this is an argument against trying to create the virtualenv during the init process.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to actually have the app entrypoint an executable file that takes care of all these details, so eventually cdk.json would be:

{
  "app": "bin/my-awesome-app"
}

@garnaat garnaat added the language/python Related to Python bindings label Apr 1, 2019
@garnaat garnaat self-assigned this Apr 1, 2019
@jfuss
Copy link
Contributor

jfuss commented Apr 1, 2019

Capturing/continuing a conversation with @garnaat from Gitter.

The current example creates a venv and a requirements.txt for customers. This is a great starting point for new customers or customers that follow these patterns. Some customers (including myself), prefer to use Pipfile and pipenv when working with Python projects. Only supporting venv would mean customers would need to generate a Pipfile from requirements.txt (you may need to configure pipenv to use the generated venv, but depends on where the venv was created). Instead, we could provide a way for a customer to tell cdk init which flavor of the example they want.

Other languages might have similar stories, so there may be a case for cdk init to generate different 'flavors' of examples (gradle vs maven for java might be a similar case).

@garnaat
Copy link
Contributor Author

garnaat commented Apr 1, 2019

Capturing/continuing a conversation with @garnaat from Gitter.

The current example creates a venv and a requirements.txt for customers. This is a great starting point for new customers or customers that follow these patterns. Some customers (including myself), prefer to use Pipfile and pipenv when working with Python projects. Only supporting venv would mean customers would need to generate a Pipfile from requirements.txt (you may need to configure pipenv to use the generated venv, but depends on where the venv was created). Instead, we could provide a way for a customer to tell cdk init which flavor of the example they want.

Other languages might have similar stories, so there may be a case for cdk init to generate different 'flavors' of examples (gradle vs maven for java might be a similar case).

I agree that there will always be multiple styles of development for any given language. We could have options like python-venv and python-pipenv to allow different starting projects.

Mitch Garnaat added 4 commits April 1, 2019 10:13
…, not an empty project. Will need to create a separate issue to move the others over and create templates for empty projects.
@garnaat
Copy link
Contributor Author

garnaat commented Apr 1, 2019

I have moved the original template over to sample-app and create a new, blank template for app. I will create a ticket to move the other incorrectly placed sample-app examples over to the right place.

Running cdk init will now produce:

Available templates:
* app: Template for a CDK Application
   └─ cdk init app --language=[csharp|fsharp|java|python|typescript]
* lib: Template for a CDK Construct Library
   └─ cdk init lib --language=typescript
* sample-app: Example CDK Application with some constructs
   └─ cdk init sample-app --language=[python|typescript]

The default choice is app so if you want the full example you need to run:

$ cdk init --language python sample-app

Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had a few previous comments unanswered


from aws_cdk import cdk

from hello.hello_stack import PyStack
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have some templating foo that you can use to generate a name for this stack and files based on the directory name in which the project was initialized (see typescript as an example). Otherwise, this means users will need to modify this after they've initialized the app and ideally they shouldn't have to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest commit uses templating.



app = cdk.App()
MyStack(app, "hello-cdk-1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put each stack in a different region (would be a nicer example)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

… use those and automatically run the python setup.py develop step. Also use templating feature for blank app.
from aws_cdk import cdk


class PyStack(cdk.Stack):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to template this guy too.... Sorry

@@ -10,8 +10,8 @@

class MyStack(cdk.Stack):

def __init__(self, app: cdk.App, id: str) -> None:
super().__init__(app, id)
def __init__(self, app: cdk.App, id: str, **kwargs) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch

aws-cdk.aws_sqs
aws-cdk.aws_sns
aws-cdk.aws_s3
-e .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oooo magic

Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

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

Successfully merging this pull request may close these issues.

6 participants