Slide 1

Slide 1 text

Kickstarting projects with Cookiecutter PyData Berlin - July 1, 2017 Raphael Pierzina

Slide 2

Slide 2 text

Thanks to the organizers for a great event!

Slide 3

Slide 3 text

$ whoami

Slide 4

Slide 4 text

Hi there! I’m Raphael

Slide 5

Slide 5 text

• Maintainer and core developer of Cookiecutter • Contributor to pytest and community person • Creator of the cookiecutter-pytest-plugin template • Software Engineer at moovel Group

Slide 6

Slide 6 text

@hackebrot

Slide 7

Slide 7 text

Agenda 1. What is Cookiecutter? 2. How does Cookiecutter work? 3. Create your own Cookiecutter template 4. Popular Cookiecutter templates 5. Demo: A custom Jupyter widget

Slide 8

Slide 8 text

1. What is Cookiecutter?

Slide 9

Slide 9 text

@hackebrot

Slide 10

Slide 10 text

@hackebrot

Slide 11

Slide 11 text

$ cookiecutter gh:pytest-dev/cookiecutter-pytest-plugin

Slide 12

Slide 12 text

full_name [Raphael Pierzina]: email [[email protected]]: github_username [hackebrot]: plugin_name [foobar]: emoji module_name [emoji]: short_description [A simple plugin to use with Pytest]: emoji plugin version [0.1.0]: pytest_version [3.1.1]: 3.1.2 Select docs_tool: 1 - mkdocs 2 - sphinx 3 - none Choose from 1, 2, 3 [1]: 1 Select license: 1 - MIT 2 - BSD-3 3 - GNU GPL v3.0 4 - Apache Software License 2.0 5 - Mozilla Public License 2.0 Choose from 1, 2, 3, 4, 5 [1]: 2 INFO:post_gen_project:Moving files for mkdocs. INFO:post_gen_project:Removing all temporary license files INFO:post_gen_project:Removing jinja2 macros py @hackebrot

Slide 13

Slide 13 text

pytest-emoji/ ├── LICENSE ├── MANIFEST.in ├── README.rst ├── appveyor.yml ├── docs │ └── index.md ├── mkdocs.yml ├── pytest_emoji.py ├── setup.py ├── tests │ ├── conftest.py │ └── test_emoji.py └── tox.ini py @hackebrot

Slide 14

Slide 14 text

Project • GitHub: https://github.com/audreyr/cookiecutter • Documentation: https://cookiecutter.readthedocs.io • PyPI: https://pypi.python.org/pypi/cookiecutter @hackebrot

Slide 15

Slide 15 text

Features • Cross-platform: Windows, Mac, and Linux are officially supported • Works with CPython 2.7, 3.3, 3.4, 3.5, 3.6 and PyPy • Project templates can be in any programming language or markup format @hackebrot

Slide 16

Slide 16 text

$ pip install cookiecutter

Slide 17

Slide 17 text

$ brew install cookiecutter

Slide 18

Slide 18 text

$ sudo apt-get install cookiecutter

Slide 19

Slide 19 text

$ conda install -c conda-forge cookiecutter

Slide 20

Slide 20 text

Community • Free and open source software: BSD license • 154 individual contributors from around the world • More than 1000 public templates on GitHub @hackebrot

Slide 21

Slide 21 text

Contributing • Development of Cookiecutter is community-driven • Connect with other Cookiecutter contributors and users on https://gitter.im/audreyr/cookiecutter • Everyone is invited to contribute! @hackebrot

Slide 22

Slide 22 text

2. How does Cookiecutter work?

Slide 23

Slide 23 text

CLI + Python API • Cookiecutter can be either used as a command- line interface app or as a Python library • Both interfaces support a number of options for controlling the level of verbosity, suppressing user prompting, providing extra context and many other things @hackebrot

Slide 24

Slide 24 text

$ cookiecutter [OPTIONS] TEMPLATE [EXTRA_CONTEXT] ...

Slide 25

Slide 25 text

$ cookiecutter -v --no-input cookiecutter-pytest-plugin license=BSD-3 docs_tool=sphinx

Slide 26

Slide 26 text

# -*- coding: utf-8 -*- from cookiecutter.main import cookiecutter def run_cookiecutter(): template = 'gh:pytest-dev/cookiecutter-pytest-plugin' project_dir = cookiecutter(template) print(f"Project generated in {project_dir}!") if __name__ == '__main__': run_cookiecutter() py @hackebrot

Slide 27

Slide 27 text

Templating with Jinja2 • Jinja2 is a modern and designer-friendly templating language for Python, modelled after Django’s templates. • It is fast, widely used and secure with the optional sandboxed template execution environment @hackebrot

Slide 28

Slide 28 text

# -*- coding: utf-8 -*- import pytest def pytest_addoption(parser): group = parser.getgroup('{{cookiecutter.plugin_name}}') group.addoption( ' --foo', action='store', dest='dest_foo', default='{% now "utc", "%Y" %}', help='Set the value for the fixture "bar".' ) parser.addini('HELLO', 'Dummy pytest.ini setting') py @hackebrot

Slide 29

Slide 29 text

{ "full_name": "Raphael Pierzina", "github_username": "hackebrot", "plugin_name": "foobar", "module_name": "{{ cookiecutter.plugin_name|lower|replace('-', '_') }}", "short_description": "A simple plugin to use with Pytest", "version": "0.1.0", "pytest_version": "3.1.1", "docs_tool": ["mkdocs", "sphinx", "none"], "license": [ "MIT", "BSD-3", "GNU GPL v3.0", "Apache Software License 2.0", "Mozilla Public License 2.0" ] } json @hackebrot

Slide 30

Slide 30 text

git + mercurial (+ zip) • Cookiecutter works with local templates on your filesystem or remote Git or Mercurial repositories • Short-hands for GitHub, BitBucket, and GitLab • Open Pull Request for adding support for templates from zip files or zip URLs (#961) @hackebrot

Slide 31

Slide 31 text

3. Create your own Cookiecutter template

Slide 32

Slide 32 text

Template project • Cookiecutter takes a source directory tree and copies it into your new project • It replaces all the names that it finds surrounded by templating tags {{ and }} with names that it finds in the cookiecutter.json file @hackebrot

Slide 33

Slide 33 text

$ mkdir hello-pydata $ cd hello-pydata $ mkdir {{cookiecutter.project_slug}} $ cd {{cookiecutter.project_slug}} @hackebrot

Slide 34

Slide 34 text

Cookiecutter namespace • Anything inside templating tags can be placed inside a namespace. • cookiecutter.project_slug will be looked up as project_slug in cookiecutter.json @hackebrot

Slide 35

Slide 35 text

$ touch {{cookiecutter.script_name}}.py @hackebrot

Slide 36

Slide 36 text

# -*- coding: utf-8 -*- def hello_pydata(): print('Hello PyData {{cookiecutter.location}}!') if __name__ == '__main__': hello_pydata() py @hackebrot

Slide 37

Slide 37 text

Context • Cookiecutter needs a context file to look up all your templates items • This file goes into our hello-pydata directory, and contains all the names we’ve used @hackebrot

Slide 38

Slide 38 text

$ cd .. $ touch cookiecutter.json @hackebrot

Slide 39

Slide 39 text

{ "project_slug": "project", "location": "World", "script_name": "hello_{{cookiecutter.location|lower}}" } json @hackebrot

Slide 40

Slide 40 text

hello-pydata/ ├── cookiecutter.json └── {{cookiecutter.project_slug}} └── {{cookiecutter.script_name}}.py py @hackebrot

Slide 41

Slide 41 text

$ cookiecutter ~/hackebrot/hello-pydata/

Slide 42

Slide 42 text

project_slug [project]: hello-project location [World]: Berlin script_name [hello_berlin]: py @hackebrot

Slide 43

Slide 43 text

hello-project/ !"" hello_berlin.py py @hackebrot

Slide 44

Slide 44 text

$ cd hello-project/ $ python hello_berlin.py Hello PyData Berlin!

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

Jinja2 syntax • {% … %} for statements • {{ … }} for expressions to print the template output • {# … #} for comments not included in the template output @hackebrot

Slide 47

Slide 47 text

Jinja2 control structures • For: Loop over each item in a sequence • If: Test if a variable is defined or if it’s equal to some other value • Macros: Useful to put often used idioms into reusable functions @hackebrot

Slide 48

Slide 48 text

{%- from "macros/rst" import doc_title, doc_subtitle -%} {{ doc_title('pytest-' + cookiecutter.plugin_name) }} rst @hackebrot

Slide 49

Slide 49 text

Jinja2 control structures • Assignments: Assign values to variables • Include: Return a rendered template into the current namespace • … @hackebrot

Slide 50

Slide 50 text

{%- if cookiecutter.license == "MIT" -%} {%- include 'licenses/MIT' %} {%- elif cookiecutter.license == "BSD-3" -%} {%- include 'licenses/BSD-3' %} {%- elif cookiecutter.license == "GNU GPL v3.0" -%} {%- include 'licenses/GPL-3' %} {%- elif cookiecutter.license == "Apache Software License 2.0" -%} {%- include 'licenses/Apache-2' %} {%- elif cookiecutter.license == "Mozilla Public License 2.0" -%} {%- include 'licenses/MPL-2' %} {%- endif -%} txt @hackebrot

Slide 51

Slide 51 text

Jinja2 filters • replace: Return a copy of the value with all occurrences of a substring replaced • lower: Convert a value to lowercase • upper: Convert a value to uppercase @hackebrot

Slide 52

Slide 52 text

{ "full_name": "Raphael Pierzina", "github_username": "hackebrot", "plugin_name": "foobar", "module_name": "{{ cookiecutter.plugin_name|lower|replace('-', '_') }}", "short_description": "A simple plugin to use with Pytest", "version": "0.1.0", "pytest_version": "3.1.1", "docs_tool": ["mkdocs", "sphinx", "none"], "license": [ "MIT", "BSD-3", "GNU GPL v3.0", "Apache Software License 2.0", "Mozilla Public License 2.0" ] } json @hackebrot

Slide 53

Slide 53 text

Jinja2 filters • tojson: Dump a structure to a JSON string • sort: Sort an iterable in ascending order by default, or descending with an extra arg. Also allows to sort by an attribute @hackebrot

Slide 54

Slide 54 text

Jinja2 filters • select: Filter a sequence of objects by applying a test to each object • groupby: Group a sequence of objects by a common attribute @hackebrot

Slide 55

Slide 55 text

Jinja2 extensions • jinja2-time: Builtin into cookiecutter to insert a string representation of a datetime object • … • … @hackebrot

Slide 56

Slide 56 text

{#- source: http: //opensource.org/licenses/MIT #} The MIT License (MIT) Copyright (c) {% now 'utc', '%Y' %} {{cookiecutter.full_name}} Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. txt @hackebrot

Slide 57

Slide 57 text

4. Popular Cookiecutter templates

Slide 58

Slide 58 text

https://github.com/audreyr/ cookiecutter-pypackage @hackebrot

Slide 59

Slide 59 text

cookiecutter-pypackage • Project structure for Python packages • Testing with unittest or pytest • Tox for testing compatibility across Python versions • Sphinx for documentation @hackebrot

Slide 60

Slide 60 text

https://github.com/pydanny/ cookiecutter-django @hackebrot

Slide 61

Slide 61 text

cookiecutter-django • Template for Django 1.10 and Python 3.4 or 3.5 • Optimized development and production settings • tests with unittest or pytest and 100% test coverage • Docker support using docker-compose • Bootstrap, 12-Factor, SSL, many other features @hackebrot

Slide 62

Slide 62 text

https://github.com/pytest-dev/ cookiecutter-pytest-plugin @hackebrot

Slide 63

Slide 63 text

cookiecutter-pytest-plugin • Installable PyPI package with comprehensive README.rst file • Tests for your plugin with tox, pytest, and CI config • Example code for a fixture, a CLI option, and a pytest.ini option • Optional documentation with either Sphinx or MkDocs • Choose from several FOSS licenses @hackebrot

Slide 64

Slide 64 text

https://github.com/pybee/ Python-iOS-template @hackebrot

Slide 65

Slide 65 text

Python-iOS-template • Generates Python apps that will run under iOS • Supports Python 2.7, 3.4, and 3.5 • Works well with the toga GUI toolkit for native iOS widgets @hackebrot

Slide 66

Slide 66 text

5. Demo: A custom Jupyter widget

Slide 67

Slide 67 text

https://github.com/jupyter- widgets/widget-cookiecutter @hackebrot

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

If you or your company are using Cookiecutter, please support its development! patreon.com/hackebrot @hackebrot

Slide 70

Slide 70 text

@hackebrot