Skip to content

Commit

Permalink
Add cookiecutter widget
Browse files Browse the repository at this point in the history
  • Loading branch information
goanpeca committed Jun 2, 2020
1 parent b70b3fd commit 2e1f570
Show file tree
Hide file tree
Showing 10 changed files with 769 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .github/scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ popd
# To check our manifest
pip install check-manifest

# TODO: update setup.py when package is avalable in defaults
pip install cookiecutter

# Create environment for Jedi environments tests
conda create -n jedi-test-env -q -y python=3.6 flask spyder-kernels
conda list -n jedi-test-env
Expand Down
1 change: 1 addition & 0 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies:
- atomicwrites >=1.2.0
- chardet >=2.0.0
- cloudpickle >=0.5.0
# - cookiecutter >=1.6.0
- diff-match-patch >=20181111
- intervaltree
- ipython >=4.0
Expand Down
1 change: 1 addition & 0 deletions requirements/conda.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ applaunchservices >=0.1.7
atomicwrites >=1.2.0
chardet >=2.0.0
cloudpickle >=0.5.0
# cookiecutter >=1.6.0
diff-match-patch >=20181111
intervaltree
IPython >=4.0
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ def run(self):
'atomicwrites>=1.2.0',
'chardet>=2.0.0',
'cloudpickle>=0.5.0',
# 'cookiecutter>=1.6.0',
'diff-match-patch>=20181111',
'intervaltree',
'ipython>=4.0',
Expand Down
54 changes: 54 additions & 0 deletions spyder/plugins/projects/utils/cookie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""
Cookiecutter utilities.
"""
import json
import os

from cookiecutter.main import cookiecutter


def generate_cookiecutter_project(cookiecutter_path, output_path,
extra_content=None):
"""
Generate a cookicutter project programmatically.
"""
status = True
try:
result = cookiecutter(
cookiecutter_path,
output_dir=output_path,
overwrite_if_exists=True,
extra_context=extra_content,
no_input=True,
)
except Exception as err:
result = err
status = False

return status, result


def load_cookiecutter_project(project_path):
"""
Load a cookicutter options and pre-hook script.
"""
options = None
pre_gen_code = None
cookiepath = os.path.join(project_path, "cookiecutter.json")
pre_gen_path = os.path.join(project_path, "hooks", "pre_gen_project.py")

if os.path.isdir(project_path):
if os.path.isfile(cookiepath):
with open(cookiepath, 'r') as fh:
options = json.loads(fh.read())

if os.path.isfile(pre_gen_path):
with open(pre_gen_path, 'r') as fh:
pre_gen_code = fh.read()

return options, pre_gen_code
9 changes: 9 additions & 0 deletions spyder/plugins/projects/utils/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) Spyder Project Contributors
#
# Licensed under the terms of the MIT License
# (see LICENSE.txt for details)
# -----------------------------------------------------------------------------

"""Tests."""
131 changes: 131 additions & 0 deletions spyder/plugins/projects/utils/tests/test_cookie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
#
"""
Tests for qcookiecutter widget.
"""
# Standard library imports
import json
import os
import shutil
import tempfile

# Third party imports
import pytest

# Local imports
from spyder.plugins.projects.utils.cookie import (generate_cookiecutter_project,
load_cookiecutter_project)


def test_load_cookiecutter_project_config():
settings = {
"opt_1": "value",
"opt_2": "{{ cookiecutter.opt_1 }}",
}
temp_path = tempfile.mkdtemp(suffix='-some-cookiecutter')
temp_cookie_path = os.path.join(temp_path, 'cookiecutter.json')

with open(temp_cookie_path, 'w') as fh:
fh.write(json.dumps(settings, sort_keys=True))

sets, pre_gen_code = load_cookiecutter_project(temp_path)
assert settings == sets
assert pre_gen_code is None

shutil.rmtree(temp_path)


def test_load_cookiecutter_project_hooks():
settings = {
"opt_1": "value",
"opt_2": "{{ cookiecutter.opt_1 }}",
}
pre_gen_code = "import sys\n\nprint('test!')\nsys.exit(1)\n"
temp_path = tempfile.mkdtemp(suffix='-some-cookiecutter')
temp_cookie_path = os.path.join(temp_path, 'cookiecutter.json')
temp_hooks_path = os.path.join(temp_path, 'hooks')
temp_hooks_pre_path = os.path.join(temp_hooks_path, 'pre_gen_project.py')
os.makedirs(temp_hooks_path)

with open(temp_cookie_path, 'w') as fh:
fh.write(json.dumps(settings, sort_keys=True))

with open(temp_hooks_pre_path, 'w') as fh:
fh.write(pre_gen_code)

sets, pre_gen_code = load_cookiecutter_project(temp_path)
assert settings == sets
assert pre_gen_code == pre_gen_code

shutil.rmtree(temp_path)


def test_generate_cookiecutter_project_defaults():
settings = {
"repo_name": "value",
}
temp_path = tempfile.mkdtemp(suffix='-some-cookiecutter')
temp_path_created = tempfile.mkdtemp(suffix='-created-project')
temp_cookie_path = os.path.join(temp_path, 'cookiecutter.json')
temp_project_path = os.path.join(temp_path, '{{cookiecutter.repo_name}}')
os.makedirs(temp_project_path)

with open(temp_cookie_path, 'w') as fh:
fh.write(json.dumps(settings, sort_keys=True))

status, result = generate_cookiecutter_project(
temp_path,
temp_path_created,
)
assert "value" in result
assert status is True
shutil.rmtree(temp_path)


def test_generate_cookiecutter_project_extra_content():
settings = {
"repo_name": "value",
}
temp_path = tempfile.mkdtemp(suffix='-some-cookiecutter')
temp_path_created = tempfile.mkdtemp(suffix='-created-project')
temp_cookie_path = os.path.join(temp_path, 'cookiecutter.json')
temp_project_path = os.path.join(temp_path, '{{cookiecutter.repo_name}}')
os.makedirs(temp_project_path)

with open(temp_cookie_path, 'w') as fh:
fh.write(json.dumps(settings, sort_keys=True))

status, result = generate_cookiecutter_project(
temp_path,
temp_path_created,
{"repo_name": "boom"},
)
assert "boom" in result
assert status is True
shutil.rmtree(temp_path)

def test_generate_cookiecutter_project_exception():
settings = {
"repo_name": "value",
}
temp_path = tempfile.mkdtemp(suffix='-some-invalid-cookiecutter')
temp_path_created = tempfile.mkdtemp(suffix='-created-project')
temp_cookie_path = os.path.join(temp_path, 'cookiecutter.json')
temp_project_path = os.path.join(temp_path, '{{cookiecutter.not_foun_variable}}')
os.makedirs(temp_project_path)

with open(temp_cookie_path, 'w') as fh:
fh.write(json.dumps(settings, sort_keys=True))

status, __ = generate_cookiecutter_project(
temp_path,
temp_path_created,
)
assert status is False


if __name__ == "__main__":
pytest.main()
Loading

0 comments on commit 2e1f570

Please sign in to comment.