Repository: audreyr/cookiecutter (python)

Issue:
pre_gen hook doesn't appear to be loading custom extensions
Latest version of cookiecutter from master. Last commit [ceafa1dc1b5eb70835ffba5dc7457df269d77ba8](https://github.com/audreyr/cookiecutter/commit/ceafa1dc1b5eb70835ffba5dc7457df269d77ba8)

In my pre_gen_project hook, I have this code: `{{cookiecutter.should_be_list | to_sequence}}` which turns a string into a list but cookiecutter raises a TemplateAssertionError `jinja2.exceptions.TemplateAssertionError: no filter named 'to_sequence'`. I know that my to_sequence filter isn't the issue because when I use it in other parts of my template and remove it from the pre_gen hook, everything executes successfully.

Are the custom extensions intended to only be loaded after the pre_gen hook is finished executing?


Pull request:
load custom extensions in pre-hook
Fixes #850 

StrictEnvironment is used instead of Template when processing the pre-hook. I changed the hooks for the tests because strings weren't getting returned.

Patch:
diff --git a/cookiecutter/generate.py b/cookiecutter/generate.py
index 68607d3..4d2f1eb 100644
--- a/cookiecutter/generate.py
+++ b/cookiecutter/generate.py
@@ -221,7 +221,13 @@ def ensure_dir_is_templated(dirname):
 
 
 def _run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context):
-    """Run hook from repo directory, clean project directory if hook fails."""
+    """Run hook from repo directory, clean project directory if hook fails.
+
+    :param repo_dir: Project template input directory.
+    :param hook_name: The hook to execute.
+    :param project_dir: The directory to execute the script from.
+    :param context: Cookiecutter project context.
+    """
     with work_in(repo_dir):
         try:
             run_hook(hook_name, project_dir, context)
diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py
index bffd5d7..413ac8c 100644
--- a/cookiecutter/hooks.py
+++ b/cookiecutter/hooks.py
@@ -9,9 +9,8 @@ import subprocess
 import sys
 import tempfile
 
-from jinja2 import Template
-
 from cookiecutter import utils
+from cookiecutter.environment import StrictEnvironment
 from .exceptions import FailedHookException
 
 logger = logging.getLogger(__name__)
@@ -106,7 +105,12 @@ def run_script_with_context(script_path, cwd, context):
         mode='wb',
         suffix=extension
     ) as temp:
-        output = Template(contents).render(**context)
+        env = StrictEnvironment(
+            context=context,
+            keep_trailing_newline=True,
+        )
+        template = env.from_string(contents)
+        output = template.render(**context)
         temp.write(output.encode('utf-8'))
 
     run_script(temp.name, cwd)


Test patch:
diff --git a/tests/test-extensions/custom-extension-post/hooks/post_gen_project.py b/tests/test-extensions/custom-extension-post/hooks/post_gen_project.py
index 3a20ca7..f26e8e1 100644
--- a/tests/test-extensions/custom-extension-post/hooks/post_gen_project.py
+++ b/tests/test-extensions/custom-extension-post/hooks/post_gen_project.py
@@ -1,4 +1,4 @@
 # -*- coding: utf-8 -*-
 # flake8: noqa
 
-print({% hello cookiecutter.name %})
+print('{% hello cookiecutter.name %}')
diff --git a/tests/test-extensions/custom-extension-pre/hooks/pre_gen_project.py b/tests/test-extensions/custom-extension-pre/hooks/pre_gen_project.py
index 3a20ca7..f26e8e1 100644
--- a/tests/test-extensions/custom-extension-pre/hooks/pre_gen_project.py
+++ b/tests/test-extensions/custom-extension-pre/hooks/pre_gen_project.py
@@ -1,4 +1,4 @@
 # -*- coding: utf-8 -*-
 # flake8: noqa
 
-print({% hello cookiecutter.name %})
+print('{% hello cookiecutter.name %}')
diff --git a/tests/test_custom_extensions_in_hooks.py b/tests/test_custom_extensions_in_hooks.py
index 84e7160..c90be5f 100644
--- a/tests/test_custom_extensions_in_hooks.py
+++ b/tests/test_custom_extensions_in_hooks.py
@@ -32,10 +32,6 @@ def modify_syspath(monkeypatch):
     )
 
 
-@pytest.mark.xfail(
-    reason='issue #850',
-    strict=True,
-)
 def test_hook_with_extension(template, output_dir):
     project_dir = main.cookiecutter(
         template,