[Python-modules-commits] [cookiecutter] 01/06: Import cookiecutter_1.4.0.orig.tar.gz

Vincent Bernat bernat at moszumanska.debian.org
Mon May 2 06:23:19 UTC 2016


This is an automated email from the git hooks/post-receive script.

bernat pushed a commit to branch master
in repository cookiecutter.

commit 2cff56151f5e99b0914d57e6202c4ce7abd84935
Author: Vincent Bernat <bernat at debian.org>
Date:   Mon May 2 08:05:04 2016 +0200

    Import cookiecutter_1.4.0.orig.tar.gz
---
 .gitignore                                         |  68 +++++++-----
 AUTHORS.rst                                        |  14 +++
 HISTORY.rst                                        |  97 ++++++++++++++++-
 README.rst                                         |  37 +++++--
 appveyor.yml                                       |   2 +
 cookiecutter/__init__.py                           |   2 +-
 cookiecutter/cli.py                                |  24 ++++-
 cookiecutter/config.py                             |  29 ++++--
 cookiecutter/environment.py                        |  52 +++++++++
 cookiecutter/exceptions.py                         |  27 +++++
 cookiecutter/generate.py                           |  63 +++++++----
 cookiecutter/main.py                               |  26 +++--
 cookiecutter/prompt.py                             |  37 ++++---
 cookiecutter/replay.py                             |  14 +--
 docs/advanced_usage.rst                            | 116 ++++++++++++++++++++-
 docs/cookiecutter.rst                              |   8 ++
 docs/troubleshooting.rst                           |   4 +-
 docs/usage.rst                                     |   2 +-
 setup.cfg                                          |   2 +-
 setup.py                                           |  24 ++---
 .../{{cookiecutter.repo_dir}}/README.rst           |   4 +-
 tests/replay/conftest.py                           |  11 +-
 tests/replay/test_dump.py                          |  23 ++--
 tests/replay/test_load.py                          |  16 +--
 tests/replay/test_replay.py                        |   4 +-
 tests/test-config/config-expand-user.yaml          |   2 +
 tests/test-config/config-expand-vars.yaml          |   2 +
 tests/test-extensions/default/cookiecutter.json    |   4 +
 .../{{cookiecutter.project_slug}}/HISTORY.rst      |   7 ++
 tests/test-extensions/unknown/cookiecutter.json    |   6 ++
 .../{{cookiecutter.project_slug}}/HISTORY.rst      |   7 ++
 .../input{{cookiecutter.binary_test}}/readme.txt   |   2 +-
 .../{{cookiecutter.binary_test}}/readme.txt        |   2 +-
 tests/test_cli.py                                  |  48 +++++++++
 tests/test_default_extensions.py                   |  41 ++++++++
 tests/test_environment.py                          |  24 +++++
 tests/test_exceptions.py                           |  21 ++++
 tests/test_generate_file.py                        |   4 +-
 tests/test_generate_files.py                       |  79 ++++++++++++++
 tests/test_get_config.py                           |   7 +-
 tests/test_get_user_config.py                      |  41 +++++---
 tests/test_main.py                                 |  41 ++++++--
 tests/test_prompt.py                               |  55 ++++++++--
 tests/test_repo_not_found.py                       |  10 ++
 .../{{cookiecutter.project_slug}}/README.rst       |   2 +
 .../{{cookiecutter.foobar}}/helloworld.py          |   0
 .../{{cookiecutter.project_slug}}/README.rst       |   6 ++
 .../undefined-variable/file-name/cookiecutter.json |   4 +
 .../{{cookiecutter.foobar}}                        |   2 +
 tox.ini                                            |   1 +
 50 files changed, 931 insertions(+), 193 deletions(-)

diff --git a/.gitignore b/.gitignore
index b3c9815..3850476 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,48 +1,62 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
 *.py[cod]
+*$py.class
 
 # C extensions
 *.so
 
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
 .installed.cfg
-lib
-lib64
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
 
 # Installer logs
 pip-log.txt
+pip-delete-this-directory.txt
 
 # Unit test / coverage reports
+htmlcov/
+.tox/
 .coverage
-.tox
+.coverage.*
 .cache
 nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
 
 # Translations
 *.mo
+*.pot
 
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-
-# Sphinx
-docs/_build
+# Django stuff:
+*.log
 
-# Coverage
-htmlcov/
+# Sphinx documentation
+docs/_build/
 
-# TextMate
-.tm_properties
+# PyBuilder
+target/
 
-# Local env
-.envs
+# PyCharm
+.idea/
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 2e736f4..1cd4893 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -77,7 +77,16 @@ Contributors
 * Valentin Lab (`@vaab`_)
 * Ilja Bauer (`@iljabauer`_)
 * Elias Dorneles (`@eliasdorneles`_)
+* Matias Saguir (`@mativs`_)
+* Johannes (`@johtso`_)
+* macrotim (`@macrotim`_)
+* Will McGinnis (`@wdm0006`_)
+* Cédric Krier (`@cedk`_)
+* Tim Osborn (`@ptim`_)
+* Aaron Gallagher (`@habnabit`_)
 
+.. _`@cedk`: https://github.com/cedk
+.. _`@johtso`: https://github.com/johtso
 .. _`@maiksensi`: https://github.com/maiksensi
 .. _`@svisser`: https://github.com/svisser
 .. _`@LucianU`: https://github.com/LucianU
@@ -142,3 +151,8 @@ Contributors
 .. _`@vaab`: https://github.com/vaab
 .. _`@iljabauer`: https://github.com/iljabauer
 .. _`@eliasdorneles`: https://github.com/eliasdorneles
+.. _`@mativs`: https://github.com/mativs
+.. _`@macrotim`: https://github.com/macrotim
+.. _`@wdm0006`: https://github.com/wdm0006
+.. _`@ptim`: https://github.com/ptim
+.. _`@habnabit`: https://github.com/habnabit
diff --git a/HISTORY.rst b/HISTORY.rst
index 96f7636..b008bf1 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,94 @@
 History
 -------
 
+1.4.0 (2016-03-20) Shortbread
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The goal of this release is changing to a strict Jinja2 environment, paving the
+way to more awesome in the future, as well as adding support for Jinja2
+extensions.
+
+New Features:
+
+* Added support for Jinja2 extension support, thanks to `@hackebrot`_ (#617).
+* Now raises an error if Cookiecutter tries to render a template that contains an undefined variable. Makes generation more robust and secure (#586). Work done by `@hackebrot`_ (#111, #586, #592)
+* Uses strict Jinja2 env in prompt, thanks to `@hackebrot`_ (#598, #613)
+* Switched from pyyaml/ruamel.yaml libraries that were problematic across platforms to the pure Python poyo_ library, thanks to `@hackebrot`_ (#557, #569, #621)
+* User config values for ``cookiecutters_dir`` and ``replay_dir`` now support
+  environment variable and user home expansion, thanks to `@nfarrar`_ for the
+  suggestion and `@hackebrot`_ for the PR (#640, #642)
+* Add `jinja2-time`_ as default extension for dates and times in templates via
+  ``{% now 'utc' %}``, thanks to `@hackebrot`_ (#653)
+
+Bug Fixes:
+
+* Provided way to define options that have no defaults, thanks to `@johtso`_ (#587, #588)
+* Make sure that ``replay.dump()`` and ``replay.load()`` use the correct user config, thanks to `@hackebrot`_ (#590, #594)
+* Added correct CA bundle for Git on Appveyor, thanks to `@maiksensi`_ (#599, #602)
+* Open ``HISTORY.rst`` with ``utf-8`` encoding when reading the changelog,
+  thanks to `@0-wiz-0`_ for submitting the issue and `@hackebrot`_ for the fix
+  (#638, #639)
+* Fix repository indicators for `private repository`_ urls, thanks to
+  `@habnabit`_ for the fix (#595) and `@hackebrot`_ for the tests (#655)
+
+.. _poyo: https://pypi.python.org/pypi/poyo
+.. _`jinja2-time`: https://pypi.python.org/pypi/jinja2-time
+.. _`private repository`: http://cookiecutter.readthedocs.org/en/latest/usage.html#works-with-private-repos
+
+Other Changes:
+
+* Set path before running tox, thanks to `@maiksensi`_ (#615, #620)
+* Removed xfail in test_cookiecutters, thanks to `@hackebrot`_ (#618)
+* Removed django-cms-plugin on account of 404 error, thanks to `@mativs`_ and `@pydanny`_ (#593)
+* Fixed docs/usage.rst, thanks to `@macrotim`_ (#604)
+* Update .gitignore to latest Python.gitignore and ignore PyCharm files, thanks to `@audreyr`_
+* Use open context manager to read context_file in generate() function, thanks to `@hackebrot`_ (#607, #608)
+* Added documentation for choice variables, thanks to `@maiksensi`_ (#611)
+* Set up Scrutinizer to check code quality, thanks to `@audreyr`_
+* Drop distutils support in setup.py, thanks to `@hackebrot`_ (#606, #609)
+* Change cookiecutter-pypackage-minimal link, thanks to `@kragniz`_ (#614)
+* Fix typo in one of the template's description, thanks to `@ryanfreckleton`_ (#643)
+* Fix broken link to `_copy_without_render`_ in *troubleshooting.rst*, thanks
+  to `@ptim`_ (#647)
+
+* Added more cookiecutter templates to the mix:
+
+  * `cookiecutter-pipproject`_ by `@wdm0006`_ (#624)
+  * `cookiecutter-flask-2`_ by `@wdm0006`_ (#624)
+  * `cookiecutter-kotlin-gradle`_ by `@thomaslee`_ (#622)
+  * `cookiecutter-tryton`_ by `@cedk`_ (#631)
+  * `django-starter`_ by `@tkjone`_ (#635)
+  * `django-docker-bootstrap`_ by `@legios89`_ (#636)
+  * `cookiecutter-mediawiki-extension`_ by `@JonasGroeger`_ (#645)
+  * `cookiecutter-django-gulp`_ by `@valerymelou`_ (#648)
+
+
+.. _`@macrotim`: https://github.com/macrotim
+.. _`@wdm0006`: https://github.com/wdm0006
+.. _`@thomaslee`: https://github.com/thomaslee
+.. _`@kragniz`: https://github.com/kragniz
+.. _`@ryanfreckleton`: https://github.com/ryanfreckleton
+.. _`@cedk`: https://github.com/cedk
+.. _`@johtso`: https://github.com/johtso
+.. _`@legios89`: https://github.com/legios89
+.. _`@0-wiz-0`: https://github.com/0-wiz-0
+.. _`@tkjone`: https://github.com/tkjone
+.. _`@nfarrar`: https://github.com/nfarrar
+.. _`@ptim`: https://github.com/ptim
+.. _`@JonasGroeger`: https://github.com/JonasGroeger
+.. _`@valerymelou`: https://github.com/valerymelou
+.. _`@habnabit`: https://github.com/habnabit
+
+.. _`cookiecutter-kotlin-gradle`: https://github.com/thomaslee/cookiecutter-kotlin-gradle
+.. _`cookiecutter-pipproject`: https://github.com/wdm0006/cookiecutter-pipproject
+.. _`cookiecutter-flask-2`: https://github.com/wdm0006/cookiecutter-flask
+.. _`django-starter`: https://github.com/tkjone/django-starter
+.. _`django-docker-bootstrap`: https://github.com/legios89/django-docker-bootstrap
+.. _`cookiecutter-mediawiki-extension`: https://github.com/JonasGroeger/cookiecutter-mediawiki-extension
+.. _`cookiecutter-django-gulp`: https://github.com/valerymelou/cookiecutter-django-gulp
+
+.. _`_copy_without_render`: http://cookiecutter.readthedocs.org/en/latest/advanced_usage.html#copy-without-render
+
 1.3.0 (2015-11-10) Pumpkin Spice
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -96,7 +184,7 @@ Other Changes:
 * Updated click requirement to < 6.0, thanks to `@pydanny`_ (#473).
 * Added landscape.io flair, thanks to `@michaeljoseph`_ (#439).
 * Descriptions of PEP8 specifications and milestone management, thanks to `@michaeljoseph`_ (#440).
-* Added alternate installation options in the documentation, thanks to `@pydanny`_  (#117, #315).
+  * Added alternate installation options in the documentation, thanks to `@pydanny`_  (#117, #315).
 * The test of the `which()` function now tests against the `date` command, thanks to `@vincentbernat`_ (#446)
 * Ensure file handles in setup.py are closed using with statement, thanks to `@svisser`_ (#280).
 * Removed deprecated and fully extraneous `compat.is_exe()` function, thanks to `@hackebrot`_ (#485).
@@ -116,7 +204,7 @@ Other Changes:
   * `cookiecutter-pytest-plugin`_ by `@pytest-dev`_ and `@hackebrot`_ (#481)
   * `cookiecutter-csharp-objc-binding`_ by `@SandyChapman`_ (#460)
   * `cookiecutter-flask-foundation`_ by `@JackStouffer`_ (#457)
-  * `cookiecutter-tryton`_ by `@fulfilio`_ (#465)
+  * `cookiecutter-tryton-fulfilio`_ by `@fulfilio`_ (#465)
   * `cookiecutter-tapioca`_ by `@vintasoftware`_ (#496)
   * `cookiecutter-sublime-text-3-plugin`_ by `@kkujawinski`_ (#500)
   * `cookiecutter-muffin`_ by `@drgarcia1986`_ (#494)
@@ -150,7 +238,7 @@ Other Changes:
 .. _`@pytest-dev`: https://github.com/pytest-dev
 .. _`cookiecutter-csharp-objc-binding`: https://github.com/SandyChapman/cookiecutter-csharp-objc-binding
 .. _`cookiecutter-flask-foundation`: https://github.com/JackStouffer/cookiecutter-Flask-Foundation
-.. _`cookiecutter-tryton`: https://github.com/fulfilio/cookiecutter-tryton
+.. _`cookiecutter-tryton-fulfilio`: https://github.com/fulfilio/cookiecutter-tryton
 .. _`cookiecutter-tapioca`: https://github.com/vintasoftware/cookiecutter-tapioca
 .. _`cookiecutter-sublime-text-3-plugin`: https://github.com/kkujawinski/cookiecutter-sublime-text-3-plugin
 .. _`cookiecutter-muffin`: https://github.com/drgarcia1986/cookiecutter-muffin
@@ -344,7 +432,7 @@ Other Changes:
 .. _`cookiecutter-kivy`: https://github.com/hackebrot/cookiecutter-kivy
 .. _`cookiecutter-ansible-role`: https://github.com/iknite/cookiecutter-ansible-role
 .. _BoilerplatePP: https://github.com/Paspartout/BoilerplatePP
-.. _`cookiecutter-pypackage-minimal`: https://github.com/borntyping/cookiecutter-pypackage-minimal
+.. _`cookiecutter-pypackage-minimal`: https://github.com/kragniz/cookiecutter-pypackage-minimal
 .. _`cookiecutter-pylibrary`: https://github.com/ionelmc/cookiecutter-pylibrary
 .. _`cookiecutter-pylibrary-minimal`: https://github.com/ionelmc/cookiecutter-pylibrary-minimal
 
@@ -359,6 +447,7 @@ Other Changes:
 .. _`@pydanny`: https://github.com/pydanny
 .. _`@saxix`: https://github.com/saxix
 .. _`@uranusjr`: https://github.com/uranusjr
+.. _`@mativs`: https://github.com/mativs
 
 
 
diff --git a/README.rst b/README.rst
index c9ce169..82ea8ab 100644
--- a/README.rst
+++ b/README.rst
@@ -28,6 +28,10 @@ Cookiecutter
         :target: https://landscape.io/github/audreyr/cookiecutter/master
         :alt: Code Health
 
+.. image:: https://img.shields.io/scrutinizer/g/audreyr/cookiecutter.svg
+        :target: https://scrutinizer-ci.com/g/audreyr/cookiecutter/?branch=master
+        :alt: Scrutinizer Code Quality
+
 A command-line utility that creates projects from **cookiecutters** (project
 templates), e.g. creating a Python package project from a Python package project template.
 
@@ -152,7 +156,9 @@ Python
 ~~~~~~
 * `cookiecutter-pypackage`_: `@audreyr`_'s ultimate Python package project
   template.
+* `cookiecutter-pipproject`_: Minimal package for pip-installable projects
 * `cookiecutter-flask`_ : A Flask template with Bootstrap 3, starter templates, and working user registration.
+* `cookiecutter-flask-2`_: A heavier weight fork of cookiecutter-flask, with more boilerplate including forgotten password and Heroku integration
 * `cookiecutter-flask-foundation`_ : Flask Template with caching, forms, sqlalchemy and unit-testing.
 * `cookiecutter-bottle`_ : A cookiecutter template for creating reusable Bottle projects quickly.
 * `cookiecutter-openstack`_: A template for an OpenStack project.
@@ -160,13 +166,14 @@ Python
 * `cookiecutter-quokka-module`_: A template to create a blueprint module for Quokka Flask CMS.
 * `cookiecutter-kivy`_: A template for NUI applications built upon the kivy python-framework.
 * `cookiedozer`_: A template for Python Kivy apps ready to be deployed to android devices with Buildozer.
-* `cookiecutter-pypackage-minimal`_: A mimimal Python package template.
+* `cookiecutter-pypackage-minimal`_: A minimal Python package template.
 * `cookiecutter-ansible-role`_: A template to create ansible roles. Forget about file creation and focus on actions.
 * `cookiecutter-pylibrary`_: An intricate template designed to quickly get started with good testing and packaging (working configuration for Tox, Pytest, Travis-CI, Coveralls, AppVeyor, Sphinx docs, isort, bumpversion, packaging checks etc).
 * `cookiecutter-pyvanguard`_: A template for cutting edge Python development. `Invoke`_, pytest, bumpversion, and Python 2/3 compatability.
 * `Python-iOS-template`_: A template to create a Python project that will run on iOS devices.
 * `Python-Android-template`_: A template to create a Python project that will run on Android devices.
-* `cookiecutter-tryton`_: A template for creating tryton modules.
+* `cookiecutter-tryton`_: A template to create base and external Tryton modules.
+* `cookiecutter-tryton-fulfilio`_: A template for creating tryton modules.
 * `cookiecutter-pytest-plugin`_: Minimal Cookiecutter template for authoring `pytest`_ plugins that help you to write better programs.
 * `cookiecutter-tapioca`_: A Template for building `tapioca-wrapper`_ based web API wrappers (clients).
 * `cookiecutter-sublime-text-3-plugin`_: Sublime Text 3 plugin template with custom settings, commands, key bindings and main menu.
@@ -179,15 +186,17 @@ Python-Django
 * `cookiecutter-django`_: A bleeding edge Django project template with Bootstrap 4, customizable users app, starter templates,  working user registration, celery setup, and much more.
 * `cookiecutter-django-rest`_: For creating REST apis for mobile and web applications.
 * `cookiecutter-simple-django`_: A cookiecutter template for creating reusable Django projects quickly.
+* `django-docker-bootstrap`_: Django development/production environment with docker, integrated with Postgres, NodeJS(React), Nginx, uWSGI.
 * `cookiecutter-djangopackage`_: A template designed to create reusable third-party PyPI friendly Django apps. Documentation is written in tutorial format.
 * `cookiecutter-django-cms`_: A template for Django CMS with simple Bootstrap 3 template. It has a quick start and deploy documentation.
-* `cookiecutter-djangocms-plugin`_: A template to get started with custom plugins for django-cms
 * `cookiecutter-django-crud`_: A template to create a Django app with boilerplate CRUD around a model including a factory and tests.
 * `cookiecutter-django-lborgav`_: Another cookiecutter template for Django project with Booststrap 3 and FontAwesome 4
 * `cookiecutter-django-paas`_: Django template ready to use in SAAS platforms like Heroku, OpenShift, etc..
 * `cookiecutter-django-rest-framework`_: A template for creating reusable Django REST Framework packages.
 * `cookiecutter-wagtail`_ : A cookiecutter template for `Wagtail`_ CMS based sites.
 * `wagtail-cookiecutter-foundation`_: A complete template for Wagtail CMS projects featuring Zurb Foundation 5, ansible provisioning and deployment , front-end dependency management with bower, modular apps to get your site up and running including photo_gallery, RSS feed etc.
+* `django-starter`_: A Django template complete with vagrant and provisioning scripts - inspired by 12 factor apps and cookiecutter-django.
+* `cookiecutter-django-gulp`_: A Cookiecutter template for integrating frontend development tools in Django projects.
 
 C
 ~~
@@ -223,6 +232,11 @@ JS
 * `cookiecutter-component`_: A template for a Component JS package.
 * `cookiecutter-tampermonkey`_: A template for a TamperMonkey browser script.
 
+Kotlin
+~~~~~~
+
+* `cookiecutter-kotlin-gradle`_: A bare-bones template for Gradle-based Kotlin projects.
+
 LaTeX/XeTeX
 ~~~~~~~~~~~
 
@@ -232,6 +246,10 @@ LaTeX/XeTeX
 
 * `cookiecutter-beamer`_: A template for a LaTeX Beamer presentation.
 
+PHP
+~~~
+
+* `cookiecutter-mediawiki-extension`_: A template for MediaWiki extensions.
 
 Berkshelf-Vagrant
 ~~~~~~~~~~~~~~~~~
@@ -247,23 +265,25 @@ HTML
 
 .. _`cookiecutter-django-rest`: https://github.com/agconti/cookiecutter-django-rest
 .. _`cookiecutter-es6-boilerplate`: https://github.com/agconti/cookiecutter-es6-boilerplate
+.. _`cookiecutter-kotlin-gradle`: https://github.com/thomaslee/cookiecutter-kotlin-gradle
 .. _`cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
 .. _`cookiecutter-jquery`: https://github.com/audreyr/cookiecutter-jquery
 .. _`cookiecutter-flask`: https://github.com/sloria/cookiecutter-flask
 .. _`cookiecutter-flask-foundation`: https://github.com/JackStouffer/cookiecutter-Flask-Foundation
 .. _`cookiecutter-bottle`: https://github.com/avelino/cookiecutter-bottle
+.. _`cookiecutter-pipproject`: https://github.com/wdm0006/cookiecutter-pipproject
+.. _`cookiecutter-flask-2`: https://github.com/wdm0006/cookiecutter-flask
 .. _`cookiecutter-simple-django`: https://github.com/marcofucci/cookiecutter-simple-django
 .. _`cookiecutter-django`: https://github.com/pydanny/cookiecutter-django
 .. _`cookiecutter-djangopackage`: https://github.com/pydanny/cookiecutter-djangopackage
 .. _`cookiecutter-django-cms`: https://github.com/palazzem/cookiecutter-django-cms
-.. _`cookiecutter-djangocms-plugin`: https://github.com/mishbahr/cookiecutter-djangocms-plugin
 .. _`cookiecutter-django-crud`: https://github.com/wildfish/cookiecutter-django-crud
 .. _`cookiecutter-quokka-module`: https://github.com/pythonhub/cookiecutter-quokka-module
 .. _`cookiecutter-django-lborgav`: https://github.com/lborgav/cookiecutter-django
 .. _`cookiecutter-django-paas`: https://github.com/pbacterio/cookiecutter-django-paas
 .. _`cookiecutter-kivy`: https://github.com/hackebrot/cookiecutter-kivy
 .. _`cookiedozer`: https://github.com/hackebrot/cookiedozer
-.. _`cookiecutter-pypackage-minimal`: https://github.com/borntyping/cookiecutter-pypackage-minimal
+.. _`cookiecutter-pypackage-minimal`: https://github.com/kragniz/cookiecutter-pypackage-minimal
 .. _`cookiecutter-ansible-role`: https://github.com/iknite/cookiecutter-ansible-role
 .. _`bootstrap.c`: https://github.com/vincentbernat/bootstrap.c
 .. _`BoilerplatePP`: https://github.com/Paspartout/BoilerplatePP
@@ -286,8 +306,10 @@ HTML
 .. _`Python-Android-template`: https://github.com/pybee/Python-Android-template
 .. _`Invoke`: http://invoke.readthedocs.org/en/latest/
 .. _`cookiecutter-django-rest-framework`: https://github.com/jpadilla/cookiecutter-django-rest-framework
-.. _`cookiecutter-tryton`: https://github.com/fulfilio/cookiecutter-tryton
+.. _`cookiecutter-tryton`: https://bitbucket.org/tryton/cookiecutter
+.. _`cookiecutter-tryton-fulfilio`: https://github.com/fulfilio/cookiecutter-tryton
 .. _`cookiecutter-beamer`: https://github.com/luismartingil/cookiecutter-beamer
+.. _`cookiecutter-mediawiki-extension`: https://github.com/JonasGroeger/cookiecutter-mediawiki-extension
 .. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin
 .. _`pytest`: http://pytest.org/latest/
 .. _`cookiecutter-tapioca`: https://github.com/vintasoftware/cookiecutter-tapioca
@@ -299,6 +321,9 @@ HTML
 .. _`cookiecutter-octoprint-plugin`: https://github.com/OctoPrint/cookiecutter-octoprint-plugin
 .. _`OctoPrint`: https://github.com/foosel/OctoPrint
 .. _`wagtail-cookiecutter-foundation`: https://github.com/chrisdev/wagtail-cookiecutter-foundation
+.. _`django-starter`: https://github.com/tkjone/django-starter
+.. _`django-docker-bootstrap`: https://github.com/legios89/django-docker-bootstrap
+.. _`cookiecutter-django-gulp`: https://github.com/valerymelou/cookiecutter-django-gulp
 
 Scala
 ~~~~~
diff --git a/appveyor.yml b/appveyor.yml
index eaad642..aadf534 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -29,6 +29,8 @@ environment:
 
 
 init:
+  - set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
+  - "git config --system http.sslcainfo \"C:\\Program Files\\Git\\mingw64\\ssl\\certs\\ca-bundle.crt\""
   - "%PYTHON%/python -V"
   - "%PYTHON%/python -c \"import struct;print(8 * struct.calcsize(\'P\'))\""
 
diff --git a/cookiecutter/__init__.py b/cookiecutter/__init__.py
index 53a354a..b5a2d66 100755
--- a/cookiecutter/__init__.py
+++ b/cookiecutter/__init__.py
@@ -8,4 +8,4 @@ cookiecutter
 Main package for Cookiecutter.
 """
 
-__version__ = '1.3.0'
+__version__ = '1.4.0'
diff --git a/cookiecutter/cli.py b/cookiecutter/cli.py
index 8825a8f..53a72fc 100755
--- a/cookiecutter/cli.py
+++ b/cookiecutter/cli.py
@@ -11,6 +11,7 @@ Main `cookiecutter` CLI.
 import os
 import sys
 import logging
+import json
 
 import click
 
@@ -18,7 +19,12 @@ from cookiecutter import __version__
 from cookiecutter.config import USER_CONFIG_PATH
 from cookiecutter.main import cookiecutter
 from cookiecutter.exceptions import (
-    OutputDirExistsException, InvalidModeException, FailedHookException
+    OutputDirExistsException,
+    InvalidModeException,
+    FailedHookException,
+    UndefinedVariableInTemplate,
+    UnknownExtension,
+    RepositoryNotFound
 )
 
 logger = logging.getLogger(__name__)
@@ -100,9 +106,23 @@ def main(template, no_input, checkout, verbose, replay, overwrite_if_exists,
             config_file=user_config
         )
     except (OutputDirExistsException,
-            InvalidModeException, FailedHookException) as e:
+            InvalidModeException,
+            FailedHookException,
+            UnknownExtension,
+            RepositoryNotFound) as e:
         click.echo(e)
         sys.exit(1)
+    except UndefinedVariableInTemplate as undefined_err:
+        click.echo('{}'.format(undefined_err.message))
+        click.echo('Error message: {}'.format(undefined_err.error.message))
+
+        context_str = json.dumps(
+            undefined_err.context,
+            indent=4,
+            sort_keys=True
+        )
+        click.echo('Context: {}'.format(context_str))
+        sys.exit(1)
 
 
 if __name__ == "__main__":
diff --git a/cookiecutter/config.py b/cookiecutter/config.py
index edfcec4..fb69b47 100755
--- a/cookiecutter/config.py
+++ b/cookiecutter/config.py
@@ -14,10 +14,7 @@ import logging
 import os
 import io
 
-try:
-    import ruamel.yaml as yaml
-except ImportError:
-    import yaml
+import poyo
 
 from .exceptions import ConfigDoesNotExistException
 from .exceptions import InvalidConfiguration
@@ -34,6 +31,13 @@ DEFAULT_CONFIG = {
 }
 
 
+def _expand_path(path):
+    """Expand both environment variables and user home in the given path."""
+    path = os.path.expandvars(path)
+    path = os.path.expanduser(path)
+    return path
+
+
 def get_config(config_path):
     """
     Retrieve the config from the specified path, returning it as a config dict.
@@ -45,17 +49,22 @@ def get_config(config_path):
     logger.debug('config_path is {0}'.format(config_path))
     with io.open(config_path, encoding='utf-8') as file_handle:
         try:
-            yaml_dict = yaml.safe_load(file_handle)
-        except yaml.scanner.ScannerError as e:
+            yaml_dict = poyo.parse_string(file_handle.read())
+        except poyo.exceptions.PoyoException as e:
             raise InvalidConfiguration(
-                '{0} is not a valid YAML file: line {1}: {2}'.format(
-                    config_path,
-                    e.problem_mark.line,
-                    e.problem))
+                'Unable to parse YAML file {}. Error: {}'
+                ''.format(config_path, e)
+            )
 
     config_dict = copy.copy(DEFAULT_CONFIG)
     config_dict.update(yaml_dict)
 
+    raw_replay_dir = config_dict['replay_dir']
+    config_dict['replay_dir'] = _expand_path(raw_replay_dir)
+
+    raw_cookies_dir = config_dict['cookiecutters_dir']
+    config_dict['cookiecutters_dir'] = _expand_path(raw_cookies_dir)
+
     return config_dict
 
 
diff --git a/cookiecutter/environment.py b/cookiecutter/environment.py
new file mode 100644
index 0000000..c07dea6
--- /dev/null
+++ b/cookiecutter/environment.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+
+from jinja2 import Environment, StrictUndefined
+
+from .exceptions import UnknownExtension
+
+
+class ExtensionLoaderMixin(object):
+    """Mixin that provides a sane way of loading extensions specified in a
+    given context.
+
+    The context is being extracted from the keyword arguments before calling
+    the next parent class in line of the child.
+    """
+    def __init__(self, **kwargs):
+        context = kwargs.pop('context', {})
+
+        default_extensions = [
+            'jinja2_time.TimeExtension',
+        ]
+        extensions = default_extensions + self._read_extensions(context)
+
+        try:
+            super(ExtensionLoaderMixin, self).__init__(
+                extensions=extensions,
+                **kwargs
+            )
+        except ImportError as err:
+            raise UnknownExtension('Unable to load extension: {}'.format(err))
+
+    def _read_extensions(self, context):
+        """Return a list of extensions as str to be passed on to the jinja2
+        env. If context does not contain the relevant info, return an empty
+        list instead.
+        """
+        try:
+            extensions = context['cookiecutter']['_extensions']
+        except KeyError:
+            return []
+        else:
+            return [str(ext) for ext in extensions]
+
+
+class StrictEnvironment(ExtensionLoaderMixin, Environment):
+    """Jinja2 environment that raises an error when it hits a variable
+    which is not defined in the context used to render a template.
+    """
+    def __init__(self, **kwargs):
+        super(StrictEnvironment, self).__init__(
+            undefined=StrictUndefined,
+            **kwargs
+        )
diff --git a/cookiecutter/exceptions.py b/cookiecutter/exceptions.py
index 415f99e..b13e768 100755
--- a/cookiecutter/exceptions.py
+++ b/cookiecutter/exceptions.py
@@ -87,3 +87,30 @@ class FailedHookException(CookiecutterException):
     """
     Raised when a hook script fails
     """
+
+
+class UndefinedVariableInTemplate(CookiecutterException):
+    """Raised when a template uses a variable which is not defined in the
+    context.
+    """
+    def __init__(self, message, error, context):
+        self.message = message
+        self.error = error
+        self.context = context
+
+    def __str__(self):
+        return (
+            "{self.message}. "
+            "Error message: {self.error.message}. "
+            "Context: {self.context}"
+        ).format(**locals())
+
+
+class UnknownExtension(CookiecutterException):
+    """Raised when an environment is unable to import a required extension."""
+
+
+class RepositoryNotFound(CookiecutterException):
+    """
+    Raised when the specified cookiecutter repository doesn't exist.
+    """
diff --git a/cookiecutter/generate.py b/cookiecutter/generate.py
index 7a4d461..5ee2934 100755
--- a/cookiecutter/generate.py
+++ b/cookiecutter/generate.py
@@ -16,16 +16,17 @@ import logging
 import os
 import shutil
 
-from jinja2 import FileSystemLoader, Template
-from jinja2.environment import Environment
-from jinja2.exceptions import TemplateSyntaxError
+from jinja2 import FileSystemLoader
+from cookiecutter.environment import StrictEnvironment
+from jinja2.exceptions import TemplateSyntaxError, UndefinedError
 from binaryornot.check import is_binary
 
 from .exceptions import (
     NonTemplatedInputDirException,
     ContextDecodingException,
     FailedHookException,
-    OutputDirExistsException
+    OutputDirExistsException,
+    UndefinedVariableInTemplate
 )
 from .find import find_template
 from .utils import make_sure_path_exists, work_in, rmtree
@@ -87,9 +88,9 @@ def generate_context(context_file='cookiecutter.json', default_context=None,
 
     context = {}
 
-    file_handle = open(context_file)
     try:
-        obj = json.load(file_handle, object_pairs_hook=OrderedDict)
+        with open(context_file) as file_handle:
+            obj = json.load(file_handle, object_pairs_hook=OrderedDict)
     except ValueError as e:
         # JSON decoding error.  Let's throw a new exception that is more
         # friendly for the developer or user.
@@ -141,7 +142,7 @@ def generate_file(project_dir, infile, context, env):
     logging.debug('Generating file {0}'.format(infile))
 
     # Render the path to the output file (not including the root project dir)
-    outfile_tmpl = Template(infile)
+    outfile_tmpl = env.from_string(infile)
 
     outfile = os.path.join(project_dir, outfile_tmpl.render(**context))
     file_name_is_empty = os.path.isdir(outfile)
@@ -181,14 +182,14 @@ def generate_file(project_dir, infile, context, env):
     shutil.copymode(infile, outfile)
 
 
-def render_and_create_dir(dirname, context, output_dir,
+def render_and_create_dir(dirname, context, output_dir, environment,
                           overwrite_if_exists=False):
     """
     Renders the name of a directory, creates the directory, and
     returns its path.
     """
 
-    name_tmpl = Template(dirname)
+    name_tmpl = environment.from_string(dirname)
     rendered_dirname = name_tmpl.render(**context)
     logging.debug('Rendered dir {0} must exist in output_dir {1}'.format(
         rendered_dirname,
@@ -255,10 +256,21 @@ def generate_files(repo_dir, context=None, output_dir='.',
 
     unrendered_dir = os.path.split(template_dir)[1]
     ensure_dir_is_templated(unrendered_dir)
-    project_dir = render_and_create_dir(unrendered_dir,
-                                        context,
-                                        output_dir,
-                                        overwrite_if_exists)
+    env = StrictEnvironment(
+        context=context,
+        keep_trailing_newline=True,
+    )
+    try:
+        project_dir = render_and_create_dir(
+            unrendered_dir,
+            context,
+            output_dir,
+            env,
+            overwrite_if_exists
+        )
+    except UndefinedError as err:
+        msg = "Unable to create project directory '{}'".format(unrendered_dir)
+        raise UndefinedVariableInTemplate(msg, err, context)
 
     # We want the Jinja path and the OS paths to match. Consequently, we'll:
     #   + CD to the template folder
@@ -273,7 +285,6 @@ def generate_files(repo_dir, context=None, output_dir='.',
     _run_hook_from_repo_dir(repo_dir, 'pre_gen_project', project_dir, context)
 
     with work_in(template_dir):
-        env = Environment(keep_trailing_newline=True)
         env.loader = FileSystemLoader('.')
 
         for root, dirs, files in os.walk('.'):
@@ -307,13 +318,24 @@ def generate_files(repo_dir, context=None, output_dir='.',
             dirs[:] = render_dirs
             for d in dirs:
                 unrendered_dir = os.path.join(project_dir, root, d)
-                render_and_create_dir(unrendered_dir, context, output_dir,
-                                      overwrite_if_exists)
+                try:
+                    render_and_create_dir(
+                        unrendered_dir,
+                        context,
+                        output_dir,
+                        env,
+                        overwrite_if_exists
+                    )
+                except UndefinedError as err:
+                    rmtree(project_dir)
+                    _dir = os.path.relpath(unrendered_dir, output_dir)
+                    msg = "Unable to create directory '{}'".format(_dir)
+                    raise UndefinedVariableInTemplate(msg, err, context)
 
             for f in files:
                 infile = os.path.normpath(os.path.join(root, f))
                 if copy_without_render(infile, context):
-                    outfile_tmpl = Template(infile)
+                    outfile_tmpl = env.from_string(infile)
                     outfile_rendered = outfile_tmpl.render(**context)
                     outfile = os.path.join(project_dir, outfile_rendered)
                     logging.debug(
@@ -324,7 +346,12 @@ def generate_files(repo_dir, context=None, output_dir='.',
                     shutil.copymode(infile, outfile)
                     continue
                 logging.debug('f is {0}'.format(f))
-                generate_file(project_dir, infile, context, env)
+                try:
+                    generate_file(project_dir, infile, context, env)
+                except UndefinedError as err:
+                    rmtree(project_dir)
+                    msg = "Unable to create file '{}'".format(infile)
+                    raise UndefinedVariableInTemplate(msg, err, context)
 
     _run_hook_from_repo_dir(repo_dir, 'post_gen_project', project_dir, context)
 
diff --git a/cookiecutter/main.py b/cookiecutter/main.py
index e6d858f..d8ff7b6 100755
--- a/cookiecutter/main.py
+++ b/cookiecutter/main.py
@@ -17,7 +17,7 @@ import os
 import re
 
 from .config import get_user_config, USER_CONFIG_PATH
-from .exceptions import InvalidModeException
+from .exceptions import InvalidModeException, RepositoryNotFound
 from .prompt import prompt_for_config
 from .generate import generate_context, generate_files
 from .vcs import clone
@@ -30,19 +30,18 @@ builtin_abbreviations = {
     'bb': 'https://bitbucket.org/{0}',
 }
 
-REPO_REGEX = """
-(
-((git|ssh|https|http):(//)?)    # something like git:// ssh:// etc.
- |                              # or
- (\w+@[\w\.]+)                  # something like user at ...
+REPO_REGEX = re.compile(r"""
+(?x)
+((((git|hg)\+)?(git|ssh|https?):(//)?)  # something like git:// ssh:// etc.
+ |                                      # or
+ (\w+@[\w\.]+)                          # something like user at ...
 )
-.*
-"""
+""")
 
 
 def is_repo_url(value):
     """Return True if value is a repository URL."""
-    return bool(re.match(REPO_REGEX, value, re.VERBOSE))
+    return bool(REPO_REGEX.match(value))
 
 
 def expand_abbreviations(template, config_dict):
@@ -112,10 +111,15 @@ def cookiecutter(
         # cookiecutters_dir
         repo_dir = template
 
+    if not os.path.isdir(repo_dir):
+        raise RepositoryNotFound(
+            'The repository {0} could not be located.'.format(template)
+        )
+
     template_name = os.path.basename(template)
 
     if replay:
-        context = load(template_name)
+        context = load(config_dict['replay_dir'], template_name)
     else:
         context_file = os.path.join(repo_dir, 'cookiecutter.json')
         logging.debug('context_file is {0}'.format(context_file))
@@ -130,7 +134,7 @@ def cookiecutter(
         # except when 'no-input' flag is set
         context['cookiecutter'] = prompt_for_config(context, no_input)
 
-        dump(template_name, context)
+        dump(config_dict['replay_dir'], template_name, context)
 
     # Create project from local context and project template.
     return generate_files(
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
index d06409c..0d7e4df 100755
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -14,7 +14,11 @@ import click
 from past.builtins import basestring
 
 from future.utils import iteritems
-from jinja2.environment import Environment
+
+from jinja2.exceptions import UndefinedError
+
+from .exceptions import UndefinedVariableInTemplate
+from .environment import StrictEnvironment
 
 
 def read_user_variable(var_name, default_value):
@@ -81,9 +85,12 @@ def read_user_choice(var_name, options):
 
 
 def render_variable(env, raw, cookiecutter_dict):
+    if raw is None:
+        return None
     if not isinstance(raw, basestring):
         raw = str(raw)
     template = env.from_string(raw)
+
     rendered_template = template.render(cookiecutter=cookiecutter_dict)
     return rendered_template
 
@@ -109,24 +116,28 @@ def prompt_for_config(context, no_input=False):
     :param no_input: Prompt the user at command line for manual configuration?
     """
     cookiecutter_dict = {}
-    env = Environment()
+    env = StrictEnvironment(context=context)
 
     for key, raw in iteritems(context[u'cookiecutter']):
         if key.startswith(u'_'):
             cookiecutter_dict[key] = raw
             continue
 
-        if isinstance(raw, list):
-            # We are dealing with a choice variable
-            val = prompt_choice_for_config(
-                cookiecutter_dict, env, key, raw, no_input
-            )
-        else:
-            # We are dealing with a regular variable
-            val = render_variable(env, raw, cookiecutter_dict)
-
-            if not no_input:
-                val = read_user_variable(key, val)
+        try:
+            if isinstance(raw, list):
+                # We are dealing with a choice variable
+                val = prompt_choice_for_config(
+                    cookiecutter_dict, env, key, raw, no_input
+                )
+            else:
+                # We are dealing with a regular variable
+                val = render_variable(env, raw, cookiecutter_dict)
+
+                if not no_input:
+                    val = read_user_variable(key, val)
+        except UndefinedError as err:
+            msg = "Unable to render variable '{}'".format(key)
+            raise UndefinedVariableInTemplate(msg, err, context)
 
         cookiecutter_dict[key] = val
     return cookiecutter_dict
diff --git a/cookiecutter/replay.py b/cookiecutter/replay.py
index 627170d..bee7ec3 100644
--- a/cookiecutter/replay.py
+++ b/cookiecutter/replay.py
@@ -11,7 +11,6 @@ import json
 import os
 from past.builtins import basestring
 
-from .config import get_user_config
 from .utils import make_sure_path_exists
 
 
@@ -20,7 +19,10 @@ def get_file_name(replay_dir, template_name):
     return os.path.join(replay_dir, file_name)
 
 
-def dump(template_name, context):
+def dump(replay_dir, template_name, context):
+    if not make_sure_path_exists(replay_dir):
+        raise IOError('Unable to create replay dir at {}'.format(replay_dir))
+
     if not isinstance(template_name, basestring):
         raise TypeError('Template name is required to be of type str')
 
@@ -30,22 +32,16 @@ def dump(template_name, context):
     if 'cookiecutter' not in context:
         raise ValueError('Context is required to contain a cookiecutter key')
 
-    replay_dir = get_user_config()['replay_dir']
-
-    if not make_sure_path_exists(replay_dir):
-        raise IOError('Unable to create replay dir at {}'.format(replay_dir))
-
     replay_file = get_file_name(replay_dir, template_name)
 
     with open(replay_file, 'w') as outfile:
         json.dump(context, outfile)
 
... 1093 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/cookiecutter.git



More information about the Python-modules-commits mailing list